宏代替GAS中的常数

时间:2011-05-05 14:29:01

标签: assembly x86 gnu gas

X86 GNU Assembly上的宏有什么问题?它表示链接期间符号S未定义。

.macro S size=40
\size
.endm

我正在使用它

mov %eax, S

2 个答案:

答案 0 :(得分:16)

宏用于为您经常使用的代码创建模板,而不是输入常数。因此,我不相信汇编程序在表达式中进行宏扩展。由于您只需要一个数字,因此可以使用.set来定义常量。

.set S, 40
mov %eax, S

此外,如果您通常使用intel语法,请确保您了解此代码正在执行的操作:它当前将eax的值存储在地址0x28的内存中。如果要将数字40放在eax中,则需要反转操作数并在S前面使用美元符号。

mov $S, %eax

答案 1 :(得分:1)

您还可以直接分配带有等号=的符号:

S = 40
GNU手册说的

等同于使用.set https://sourceware.org/binutils/docs-2.19/as/Setting-Symbols.html#Setting-Symbols

  

可以通过编写符号来给符号赋予任意值,后跟等号=', followed by an expression (see Expressions). This is equivalent to using the .set directive. See .set. In the same way, using a double equals sign ='`='在此表示.eqv指令的等效项。参见.eqv。

.equ是另一个同义词...

 .equ S, 40

此类常量的一种典型用例是计算静态字符串的长度,例如Linux x86_64的hello世界可以写成:

    .data
hello_world:
    .ascii "hello world\n"
    hello_world_len = . - hello_world
.text
.global _start
_start:
    /* write */
    mov $1, %rax
    mov $1, %rdi
    mov $hello_world, %rsi
    mov $hello_world_len, %rdx
    syscall

    /* exit */
    mov $60, %rax
    mov $0, %rdi
    syscall

您可以编译并运行:

as -o hello_world.o hello_world.S
ld -o hello_world.out hello_world.o
./hello_world.out

%rdx将包含要写入的字符串的长度。

$是必需的,就像任何常规地址标签一样,否则,您将尝试访问该内存地址而不是立即移动。

相关问题