|
先写个简单的程序
- #include <stdio.h>
- int main()
- {
- printf("Hello,world\n");
- return 0;
- }
复制代码 然后分别在4种情况下编译:
1. 使用主系统的gcc, binutils,和glibc
先编译: gcc -v -c test.c
输出如下红色是我加的注释)
Using built-in specs.
[color="Red"]#疑问1: 什么是内建的specs? 什么时候不用内建的specs?
Target: i686-pc-linux-gnu
Configured with: ../gcc-4.4.0/configure --prefix=/usr --libexecdir=/usr/lib --enable-shared --enable-threads=posix --enable-__cxa_atexit --enable-clocale=gnu --enable-languages=c,c++ --disable-bootstrap
Thread model: posix
[color="Red"]疑问2: 还有什么thread model?
gcc version 4.4.0 (GCC)
COLLECT_GCC_OPTIONS='-v' '-c' '-mtune=generic'
/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/cc1 -quiet -v test.c -quiet -dumpbase test.c -mtune=generic -auxbase test -version -o /tmp/ccMeTqhk.s
[color="Blue"]#第一步用cc1, 将C语言变为汇编文件,在/tmp下
[color="Red"]疑问3: -mtune是什么? 都有什么-mtune?
ignoring nonexistent directory "/usr/local/include"
ignoring nonexistent directory "/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/../../../../i686-pc-linux-gnu/include"
[color="Blue"]这是干什么?!
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/include
/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/include-fixed
[color="Red"]疑问4: 这些目录下都有啥? 什么程序用这些目录下的头文件?
/usr/include
End of search list.
GNU C (GCC) version 4.4.0 (i686-pc-linux-gnu)
compiled by GNU C version 4.4.0, GMP version 4.3.1, MPFR version 2.4.1.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 38b1ddb0d964ccbe49d98b715e55457e
COLLECT_GCC_OPTIONS='-v' '-c' '-mtune=generic'
as -V -Qy -o test.o /tmp/ccMeTqhk.s
[color="Red"]#第二步, 用binutils的as将汇编语言转换成object
GNU assembler version 2.19.1 (i686-pc-linux-gnu) using BFD version (GNU Binutils) 2.19.1
COMPILER_PATH=/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/:/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/:/usr/lib/gcc/i686-pc-linux-gnu/:/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/:/usr/lib/gcc/i686-pc-linux-gnu/:/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/:/usr/lib/gcc/i686-pc-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/:/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/:/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-c' '-mtune=generic'
OPSvr root #
OK, 我们先看看第一步输出的汇编语言
- OPSvr tmp #cat ccMeTqhk.s
- .file "test.c"
- .section .rodata
- .LC0:
- .string "Hello,world"
- .text
- .globl main
- .type main, @function
- main:
- pushl %ebp
- movl %esp, %ebp
- andl $-16, %esp
- subl $16, %esp
- movl $.LC0, (%esp)
- call puts
- movl $0, %eax
- leave
- ret
- .size main, .-main
- .ident "GCC: (GNU) 4.4.0"
- .section .note.GNU-stack,"",@progbits
复制代码
Kao.. 由于printf没有参数,直接换成简单点的puts了. 这里面除了puts的函数名,没其他任何关于glibc的信息. 主要有两个段: .rodate和.text, 还有一个不知道要干嘛的.note.GNU-stack段.
再看看第二步的输出:
- OPSvr root #readelf -a test.o
- ELF Header:
- Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
- Class: ELF32
- Data: 2's complement, little endian
- Version: 1 (current)
- OS/ABI: UNIX - System V
- ABI Version: 0
- Type: REL (Relocatable file)
- Machine: Intel 80386
- Version: 0x1
- Entry point address: 0x0
- Start of program headers: 0 (bytes into file)
- Start of section headers: 192 (bytes into file)
- Flags: 0x0
- Size of this header: 52 (bytes)
- Size of program headers: 0 (bytes)
- Number of program headers: 0
- Size of section headers: 40 (bytes)
- Number of section headers: 11
- Section header string table index: 8
- Section Headers:
- [Nr] Name Type Addr Off Size ES *** Lk Inf Al
- [ 0] NULL 00000000 000000 000000 00 0 0 0
- [ 1] .text PROGBITS 00000000 000034 00001c 00 AX 0 0 4
- [ 2] .rel.text REL 00000000 00032c 000010 08 9 1 4
- [ 3] .data PROGBITS 00000000 000050 000000 00 WA 0 0 4
- [ 4] .bss NOBITS 00000000 000050 000000 00 WA 0 0 4
- [ 5] .rodata PROGBITS 00000000 000050 00000c 00 A 0 0 1
- [ 6] .comment PROGBITS 00000000 00005c 000012 00 0 0 1
- [ 7] .note.GNU-stack PROGBITS 00000000 00006e 000000 00 0 0 1
- [ 8] .shstrtab STRTAB 00000000 00006e 000051 00 0 0 1
- [ 9] .symtab SYMTAB 00000000 000278 0000a0 10 10 8 4
- [10] .strtab STRTAB 00000000 000318 000012 00 0 0 1
- Key to Flags:
- W (write), A (alloc), X (execute), M (merge), S (strings)
- I (info), L (link order), G (group), x (unknown)
- O (extra OS processing required) o (OS specific), p (processor specific)
- There are no section groups in this file.
- There are no program headers in this file.
- Relocation section '.rel.text' at offset 0x32c contains 2 entries:
- Offset Info Type Sym.Value Sym. Name
- 0000000c 00000501 R_386_32 00000000 .rodata
- 00000011 00000902 R_386_PC32 00000000 puts
- There are no unwind sections in this file.
- Symbol table '.symtab' contains 10 entries:
- Num: Value Size Type Bind Vis Ndx Name
- 0: 00000000 0 NOTYPE LOCAL DEFAULT UND
- 1: 00000000 0 FILE LOCAL DEFAULT ABS test.c
- 2: 00000000 0 SECTION LOCAL DEFAULT 1
- 3: 00000000 0 SECTION LOCAL DEFAULT 3
- 4: 00000000 0 SECTION LOCAL DEFAULT 4
- 5: 00000000 0 SECTION LOCAL DEFAULT 5
- 6: 00000000 0 SECTION LOCAL DEFAULT 7
- 7: 00000000 0 SECTION LOCAL DEFAULT 6
- 8: 00000000 28 FUNC GLOBAL DEFAULT 1 main
- 9: 00000000 0 NOTYPE GLOBAL DEFAULT UND puts
- No version information found in this file.
复制代码
可以看到蹦出了一堆段.
.text 从0x34开始,长0x1c
.rodata从0x50开始, 长0x0c
.rel.text指明了需要重定位的信息, 包括.rodata需要重新定位, puts需要重新定位. 谁来定位呢? puts需要在程序启动后动态定位
.data, .bss 程序中没有,程度都为0
.comment 干嘛用的? 18字节长 GCC: (GNU) 4.4.0
.shstrtab 从0x6e开始, 长0x51
.symtab从0x278开始,长0xa0
.strtab从138开始,长0x12
[color="Red"]疑问5, .shstrtab, .symtab, .strtab 干嘛用的?
反汇编一下, 看看和源码的区别:
- OPSvr root #objdump -S test.o
- test.o: file format elf32-i386
- Disassembly of section .text:
- 00000000 <main>:
- 0: 55 push %ebp
- 1: 89 e5 mov %esp,%ebp
- 3: 83 e4 f0 and $0xfffffff0,%esp
- 6: 83 ec 10 sub $0x10,%esp
- 9: c7 04 24 00 00 00 00 movl $0x0,(%esp)
- 10: e8 fc ff ff ff call 11 <main+0x11>
- 15: b8 00 00 00 00 mov $0x0,%eax
- 1a: c9 leave
- 1b: c3 ret
复制代码
可以看出 $.LC0 直接变为0x0,
puts变为 <main+0x11> , 期待链接程序重新赋值
先不管它,我们接着进行第二步, 链接glibc.
OPSvr root #gcc -v -o test test.o
Using built-in specs.
Target: i686-pc-linux-gnu
Configured with: ../gcc-4.4.0/configure --prefix=/usr --libexecdir=/usr/lib --enable-shared --enable-threads=posix --enable-__cxa_atexit --enable-clocale=gnu --enable-languages=c,c++ --disable-bootstrap
Thread model: posix
gcc version 4.4.0 (GCC)
COMPILER_PATH=/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/:/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/:/usr/lib/gcc/i686-pc-linux-gnu/:/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/:/usr/lib/gcc/i686-pc-linux-gnu/:/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/:/usr/lib/gcc/i686-pc-linux-gnu/
[color="Red"]#这是在干嘛? 这么多重复的路径?!
LIBRARY_PATH=/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/:/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/:/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/../../../:/lib/:/usr/lib/
[color="Red"]#这个/usr/lib也重复了.. 电脑不糊涂,人脑糊涂了..
COLLECT_GCC_OPTIONS='-v' '-o' 'test' '-mtune=generic'
/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/collect2
[color="Red"]疑问6: 为什么用collect2, 不用ld?
--eh-frame-hdr
-m elf_i386
-dynamic-linker
/lib/ld-linux.so.2
-o test
/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/../../../crt1.o
#其实就是/usr/lib/crt1.o
[color="Red"]#疑问7 crt1.o是干嘛用的? gcc提供的还是glibc提供的?
/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/../../../crti.o
其实就是/usr/lib/crti.o
[color="Red"]疑问8 crti.o是干嘛用的? gcc提供的还是glibc提供的?
/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/crtbegin.o
疑问九 crtbegin.o是干嘛用的? gcc提供的还是glibc提供的?
-L/usr/lib/gcc/i686-pc-linux-gnu/4.4.0
-L/usr/lib/gcc/i686-pc-linux-gnu/4.4.0
-L/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/../../.. test.o
-lgcc
[color="Red"]疑问10, gcc库是干嘛用的?
--as-needed -lgcc_s
[color="Red"]疑问11, gcc_s库是干嘛用的?
--no-as-needed -lc
[color="Red"]疑问12, c库是glibc提供的?
-lgcc
[color="Red"]怎么又来一遍?!
--as-needed -lgcc_s
--no-as-needed /usr/lib/gcc/i686-pc-linux-gnu/4.4.0/crtend.o
[color="Red"]疑问13, crtend.o是干嘛用的?
/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/../../../crtn.o
[color="Red"]疑问14, crtn.o是干嘛用的?
Kao..晕了 链接一个简单的程序,需要这么这么多来自gcc和glibc的库... |
|