关于x86_64架构下AT&T格式汇编Hello World程序的编译与正确性疑问
关于x86_64架构下AT&T格式汇编Hello World程序的编译与正确性疑问
嘿,很高兴看到你在手动编写调用系统调用的汇编程序,这可是深入理解Linux底层运作的好方式!咱们逐个解决你的疑问:
1. .s 和 .S 后缀的区别,以及编译方式的正确性
首先得明确这两个后缀的规范含义:
- 小写的
.s:代表已经完成预处理的汇编源文件,文件里不包含任何C预处理器指令(比如#define、#include这类),可以直接用as汇编成目标文件。 - 大写的
.S:代表需要经过预处理的汇编源文件,文件里可以包含C预处理器支持的语法,比如宏定义、头文件引用。这类文件不能直接用as编译——如果你强行用as hello.S -o hello.o,预处理器指令会被当成无效的汇编语法报错。正确的做法是用gcc -c hello.S -o hello.o,gcc会自动先调用cpp(C预处理器)处理文件,再调用as汇编。
回到你的情况:你的代码里没有任何预处理器指令,所以即使把文件命名为.S,直接用as编译也能正常工作(因为没有需要预处理的内容),但从命名规范来说,用.s更准确,能清晰告诉别人这个汇编文件不需要预处理。
2. 为什么 gcc -S demo.i 生成 demo.s 而不是 demo.S
demo.i是已经完成预处理的C源文件——它已经展开了所有宏、头文件,没有任何需要再处理的预处理器指令了。gcc把它编译成汇编代码时,生成的是不需要再预处理的汇编文件,所以按照规范用.s后缀,符合“已预处理汇编文件”的定义。
3. 你的Hello World汇编代码是否100%正确?
从功能和正确性来说,你的代码完全没问题:
- 你正确使用了x86_64 Linux的系统调用约定:
rax存系统调用号(1对应write,60对应exit),参数依次存在rdi、rsi、rdx里。 lea msg(%rip), %rsi是正确的位置无关代码(PIC)写法,符合现代Linux默认的PIC可执行文件要求,能确保程序在不同内存地址都能正常运行。.set msglen, (. - msg)的方式计算字符串长度非常准确,因为.rodata段是连续存储的,当前位置减去msg的地址就是字符串的字节数。
不过有个小细节可以提一下:在x86_64的System V ABI中,main函数的返回值是通过rax寄存器返回给调用者(也就是C运行时),你的代码直接调用exit系统调用退出,这完全没问题——很多纯汇编写的程序都会这么做,毕竟exit系统调用是直接终止进程,跳过了C运行时的收尾步骤,对于简单程序来说完全够用。
总结:你的代码功能完全正确,写法也符合x86_64 Linux的规范,放心用就好!
备注:内容来源于stack exchange,提问作者Kode1000




