gcc编译时文件扩展名为.S和.s的区别
- 2020 年 2 月 17 日
- 筆記
gcc编译时,文件扩展名为.S和.s的区别是,.S支持预处理,而.s不支持。
gcc编译一般分为四个阶段,分别是预处理、编译、汇编、链接。
下面我们用一个小例子看下这四个阶段的作用,示例代码:
#ifndef __LIB_H
预处理的作用是宏展开和头文件替换:
$ gcc -E main.c -o main.i $ cat main.i // 删除一些无关内容 extern int add(int a, int b); int main() { return add(1, 2); }
编译的作用是把c代码转成汇编代码:
$ gcc -fno-asynchronous-unwind-tables -S main.i $ ls lib.c lib.h main.c main.i main.s $ cat main.s .file "main.c" .text .globl main .type main, @function main: pushq %rbp movq %rsp, %rbp movl $2, %esi movl $1, %edi call add@PLT popq %rbp ret .size main, .-main .ident "GCC: (GNU) 9.2.0" .section .note.GNU-stack,"",@progbits
汇编的作用是将汇编代码转成对应的二进制形式的cpu指令:
$ gcc -c main.s $ ls lib.c lib.h main.c main.i main.o main.s $ file main.o main.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
链接的作用是把代码之间的引用关系关联起来,最终生成一个完整的程序:
$ gcc -c lib.c $ ls lib.c lib.h lib.o main.c main.i main.o main.s $ gcc main.o lib.o $ ls a.out lib.c lib.h lib.o main.c main.i main.o main.s $ ./a.out; echo $? 3
由上可见,文件扩展名为.s的文件其实就是汇编代码文件。
其实我们可以直接编写汇编代码,保存到以.s为后缀的文件里,然后再用gcc将其编译成可执行文件。
但.s为后缀的文件不支持预处理,如果我们想在汇编代码里使用宏或头文件,则保存该汇编代码的文件必须以.S结尾。
写个例子看下:
$ cat hello.s #define MSG "hello" .global main .text main: mov $message, %rdi call puts ret message: .asciz MSG $ gcc -no-pie hello.s hello.s: Assembler messages: hello.s:10: Error: junk at end of line, first unrecognized character is `M' $ mv hello.s hello.S $ gcc -no-pie hello.S $ ./a.out hello
由上可见,当文件扩展名为.s时,宏MSG是无法识别的,但扩展名改为.S后,该汇编代码可正常编译并执行。
希望对你有所帮助。