mov a(%rip), %rax
loads from a
.
(So would mov a, %rax
but don't do that; you always want RIP-relative or an integer register for addressing static storage in x86-64.)
I think what you're missing is that .extern
is like in C++: it declares that the symbol is defined elsewhere, in a different object file. So the above would assemble but then not link into an executable unless you linked with another .o
e.g. from compiling long a = 1;
at global scope in a .c
In GAS .extern
is a no-op because that's already assumed for symbol names that aren't defined in the current asm file. See the manual.
Perhaps you wanted to reserve some space in the .data
section and put a label on that space, like a C compiler would when you declare a global variable:
long a;
long main(){ // with int main GCC optimizes to loading only EAX
return a;
}
compiles with GCC -O2 (Godbolt) to the following asm, boiled down to the parts you'd want to keep for a hand-written version:
main:
mov a(%rip), %rax
ret
.comm a,8,8 # reserve 8 bytes in the BSS and call it a
If we'd used long a = 1;
(a non-zero initializer):
.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
In general you can learn asm syntax from compiler output if you know what to look for, and compile simple enough C files. (How to remove "noise" from GCC/clang assembly output?) But some of the essential parts (e.g. .section
) is mostly noise if you know what to expect so Godbolt filters it out. And to see it you have to also see .size
and .type
declarations which you don't need to worry about as a beginner.