mov a(%rip), %rax 从 a 加载。
(mov a, %rax 也可以,但不要那样做;您总是需要 RIP-relative 或整数寄存器来寻址 x86-64 中的静态存储。)
我认为您缺少的是 .extern 就像在 C++ 中一样:它声明符号是在不同的目标文件中定义的其他地方。因此,除非您与另一个 .o 链接,否则上述内容将组装但不会链接到可执行文件中,例如来自在 .c 的全局范围内编译 long a = 1;
在 GAS 中 .extern 是无操作的,因为对于当前 asm 文件中未定义的符号名称已经假定了这一点。 See the manual。
也许您想在 .data 部分保留一些空间并在该空间上放置标签,就像 C 编译器在声明全局变量时所做的那样:
long a;
long main(){ // with int main GCC optimizes to loading only EAX
return a;
}
使用 GCC -O2 (Godbolt) 编译为以下 asm,归结为您想要保留的手写版本的部分:
main:
mov a(%rip), %rax
ret
.comm a,8,8 # reserve 8 bytes in the BSS and call it a
如果我们使用long a = 1;(非零初始化器):
.data # switch to the .data section
.globl a # declare a as externally visible, like a C global not static
a: # a label declares a symbol with address = this position
.quad 1 # a qword with integer value 1
一般来说,如果您知道要查找什么,则可以从编译器输出中学习 asm 语法,并编译足够简单的 C 文件。 (How to remove "noise" from GCC/clang assembly output?) 但是如果你知道会发生什么,那么一些重要的部分(例如.section)主要是噪音,所以 Godbolt 将其过滤掉。要查看它,您还必须查看 .size 和 .type 声明,作为初学者无需担心。