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后,该汇编代码可正常编译并执行。

希望对你有所帮助。