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後,該彙編程式碼可正常編譯並執行。
希望對你有所幫助。