GAS supports the *
operators for assemble-time multiplication of constants. For example, mov $(5 * 50), %eax
assembles to exactly the same machine code as mov $250, %eax
. Other operators like + - / %, and bitwise stuff are also available. I'll just use *
for the examples, but you can construct arbitrary expressions out of compile-time constants as long as they evaluate to a single number (or offset from a symbol that the linker can resolve).
This works with assembler constants like .equ A, 50
or A = 50
as well.
.equ A, 50
.equ B, 5
aa = 3
bb = 7
.globl _start
_start: # machine code .intel_syntax disassembly
mov $(5 * 50), %eax # b8 fa 00 00 00 mov eax,0xfa # 250
mov $(aa * B), %ecx # b9 0f 00 00 00 mov ecx,0xf # 3*5 = 15
mov $A * B, %edx # ba fa 00 00 00 mov edx,0xfa # 250
Note that the whole immediate constant only uses one $
, rather than a $
on every symbol name. For example, mov $(5 + $A), %eax
tries to put the address of a symbol called $A
(plus 5) into %eax
, so you get a link-time error for an undefined symbol.
mov $( $A * $B ), %eax
doesn't even assemble:
Error: invalid operands (*UND* and *UND* sections) for '*'
This is because you're trying to multiply the address of two unknown symbols ($A
and $B
), rather than your assembler constants A
and B
.
In GAS, all symbols have an associated section. When you define a symbol with .equ
or =
, it's an "absolute" symbol (rather than a .data
section or .text
section symbol like you'd get from a label like A:
).
Assembler constants aren't really different from symbols defined with labels. However, other than +
and -
, all assemble-time math operators require both args to be absolute, and the result is absolute.
Your code appears to be trying to put the constants into registers to multiply them at runtime. If you insist on doing that as an exercise,
mov $A, %ecx # put symbol's value in ECX
imul $B, %ecx, %eax # EAX = A * B
mov A, %eax
is a load from the symbol's value. i.e. a load from absolute address 50
, which obviously segfaults. Single-step with a debugger and look at the disassembly to understand what happened.
AT&T syntax uses $
for immediate constants, so use that to get the value. (Remember, .equ
symbols behave the same as labels, like how you'd use $my_string
to get the address as an immediate.)