In AT & T $ syntax, it means treating what follows as an immediate constant, not a memory address. In other words,
movl $_start, %eax
loads the address of the _start character in% eax;
movl _start, %eax
reads 4 bytes from memory at _start in% eax. If you look at disassembling both:
0: b8 00 00 00 00 mov $0x0,%eax 1: R_386_32 _start 5: a1 00 00 00 00 mov 0x0,%eax 6: R_386_32 _start
you can see that the only difference is the operation code. The convenient, albeit somewhat arrogant, Intel® 64 and IA-32 Developer Software Developer's Guide (you need volume 2, which is the set reference instruction) says that the B8-BF encode opcode "downloads an immediate 16/32-bit constant to register "(this is a code intended to be loaded into a 32-bit code segment, therefore it has a 32-bit load, for 16-bit loading, you must have a prefix byte of operand size, code 66), and operation code A1 encodes" loads a 32-bit quantity at the specified 32-bit offset from DS ( Does any other segment with the appropriate prefix byte) in EAX ". With a typical “flat” memory model, that’s the moral equivalent of “32-bit load at the specified 32-bit absolute address,” but you can see how x86 got its reputation as ridiculously complex at the machine level.
In case you are interested, it will look like this if we used EBX:
a: bb 00 00 00 00 mov $0x0,%ebx b: R_386_32 _start f: 8b 1d 00 00 00 00 mov 0x0,%ebx 11: R_386_32 _start
Download-immediate can still be performed with a single-byte instruction, not counting the operand (this is BB instead of B9, as you would expect, because the internal register is AX, CX, DX, BX, SP, BP, SI, DI - seriously), but now shipped from the absolute address has a two-byte instruction, 8B 1D; the second byte is what Intel calls the “ModRM” byte, which indicates both EBX and the absolute 4-byte address.