gcc编译和目标文件

gcc编译和目标文件

  • 1 基本概念
    • 1.1 链接过程类型
    • 1.2 目标文件形式
  • 2 Gcc编译过程示例
    • 2.1 示例代码
    • 2.2 预处理
      • 2.2.1 main.i
      • 2.2.2 add.i
    • 2.3 编译
      • 2.3.1 main.s
    • 2.4 汇编和反汇编
      • 2.4.1 main.o
      • 2.4.2 add.o
    • 2.5 链接
    • 2.6 相关命令汇总
  • 3 可执行文件分析
    • 3.1 可执行ELF文件空间布局
    • 3.2 可执行文件反编译
      • 3.2.1 文件基本信息
      • 3.2.2 程序头部表信息
      • 3.2.3 段信息
      • 3.2.4 符号表信息
      • 3.2.5 反汇编信息
  • 4 加载可执行目标文件
    • 4.1 运行时内存映像
  • 5 参考资料

1 基本概念

Gcc编译4阶段:预处理、编译、汇编、链接

预处理(cpp):处理头文件、宏定义、条件编译等;
编译(ccl):代码检查,生成.s汇编文件;
汇编(as):生成可重定位(全局、外部函数等符号)的.o目标文件;
链接过程(ld):把所有代码和数据组合到单个文件,这个文件可以被加载到内存中执行。

1.1 链接过程类型

编译期链接:针编译可执行文件过程时对静态库、可重定位目标文件的链接
加载期链接:针对动态库的运行时链接,在被加载器加载到内存执行时。
运行时链接:针对动态库,由应用程序来动态加载库文件,相关函数如:dladdr, dlclose, dlerror, dlopen, dlsym, dlvsym。Java本地接口即通过运行时链接方式动态链接和加载使用C/C++编译生成的动态链接库。

1.2 目标文件形式

可重定位目标文件:编译、汇编后的.o目标文件,可重定位;
可执行目标文件:二进制可执行目标文件,静态链接后的bin文件
共享目标文件:动态链接库

2 Gcc编译过程示例

2.1 示例代码

三个文件
add.h文件内容:
int add(int a,int b);
add.c文件内容:
int add(int a,int b)
{
return a+b;
}
main.c文件内容:
#include “add.h”
int a = 1;
int b = 2;

int main()
{
int res=add(a,b);
}

2.2 预处理

2.2.1 main.i

gcc -E main.c -o main.i
生成对main.c预处理后的main.i文件

# 1 "main.c"# 1 "<built-in>"# 1 "<command-line>"# 1 "/usr/include/stdc-predef.h" 1 3 4# 1 "<command-line>" 2# 1 "main.c"# 1 "add.h" 1int add(int a,int b);# 2 "main.c" 2int a = 1;int b = 2;int main(){ int res=add(a,b);}

2.2.2 add.i

# 1 "add.c"# 1 "<built-in>"# 1 "<command-line>"# 1 "/usr/include/stdc-predef.h" 1 3 4# 1 "<command-line>" 2# 1 "add.c"int add(int a,int b){ return a+b;}

2.3 编译

2.3.1 main.s

cc1 -m32 main.i -o main.s
生成汇编文件main.s
备注:
1、 这里以32bit进行编译
2、 若提示命令找不到,原因是cc1所在目录不在$PATH环境变量中,可使用可使用绝对路径,如/usr/lib/gcc/x86_64-linux-gnu/4.8.4/cc1 -m32 main.i -o main.s
3、 cc1第3个字符是数字1,不是字母l

.file"main.i".globla.data.align 4.typea, @object.sizea, 4a:.long1.globlb.align 4.typeb, @object.sizeb, 4b:.long2.text.globlmain.typemain, @functionmain:.LFB0:.cfi_startprocpushq%rbp.cfi_def_cfa_offset 16.cfi_offset 6, -16movq%rsp, %rbp.cfi_def_cfa_register 6subq$16, %rspmovlb(%rip), %edxmovla(%rip), %eaxmovl%edx, %esimovl%eax, %edicalladdmovl%eax, -4(%rbp)leave.cfi_def_cfa 7, 8ret.cfi_endproc.LFE0:.sizemain, .-main.ident"GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.4) 4.8.4".section.note.GNU-stack,"",@progbits2.3.2add.s.file"add.i".text.globladd.typeadd, @functionadd:.LFB0:.cfi_startprocpushl%ebp.cfi_def_cfa_offset 8.cfi_offset 5, -8movl%esp, %ebp.cfi_def_cfa_register 5movl12(%ebp), %eaxmovl8(%ebp), %edxaddl%edx, %eaxpopl%ebp.cfi_restore 5.cfi_def_cfa 4, 4ret.cfi_endproc.LFE0:.sizeadd, .-add.ident"GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.4) 4.8.4".section.note.GNU-stack,"",@progbits

2.4 汇编和反汇编

as --32 -o main.o main.s
生成可重定位目标文件main.o

2.4.1 main.o

此文件不好使用cat直接查看,会显示一堆乱码。

可使用objdump进行反汇编命令选项查看:
objdump -dx main.o
-d:反汇编
-x:显示所有header
命令结果显示如下:

main.o:     file format elf32-i386main.oarchitecture: i386, flags 0x00000011:HAS_RELOC, HAS_SYMSstart address 0x00000000Sections:Idx Name          Size      VMA       LMA       File off  Algn  0 .text         00000026  00000000  00000000  00000034  2**0                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE  1 .data         00000008  00000000  00000000  0000005c  2**2                  CONTENTS, ALLOC, LOAD, DATA  2 .bss          00000000  00000000  00000000  00000064  2**0                  ALLOC  3 .comment      0000002c  00000000  00000000  00000064  2**0                  CONTENTS, READONLY  4 .note.GNU-stack 00000000  00000000  00000000  00000090  2**0                  CONTENTS, READONLY  5 .eh_frame     00000038  00000000  00000000  00000090  2**2                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATASYMBOL TABLE:00000000 l    df *ABS*00000000 main.i00000000 l    d  .text00000000 .text00000000 l    d  .data00000000 .data00000000 l    d  .bss00000000 .bss00000000 l    d  .note.GNU-stack00000000 .note.GNU-stack00000000 l    d  .eh_frame00000000 .eh_frame00000000 l    d  .comment00000000 .comment00000000 g     O .data00000004 a00000004 g     O .data00000004 b00000000 g     F .text00000026 main00000000         *UND*00000000 addDisassembly 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 20             sub    $0x20,%esp   9:8b 15 00 00 00 00    mov    0x0,%edxb: R_386_32b   f:a1 00 00 00 00       mov    0x0,%eax10: R_386_32a  14:89 54 24 04          mov    %edx,0x4(%esp)  18:89 04 24             mov    %eax,(%esp)  1b:e8 fc ff ff ff       call   1c <main+0x1c>1c: R_386_PC32add  20:89 44 24 1c          mov    %eax,0x1c(%esp)  24:c9                   leave    25:c3                   ret    

2.4.2 add.o

main.o:     file format elf32-i386main.oarchitecture: i386, flags 0x00000011:HAS_RELOC, HAS_SYMSstart address 0x00000000Sections:Idx Name          Size      VMA       LMA       File off  Algn  0 .text         00000026  00000000  00000000  00000034  2**0                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE  1 .data         00000008  00000000  00000000  0000005c  2**2                  CONTENTS, ALLOC, LOAD, DATA  2 .bss          00000000  00000000  00000000  00000064  2**0                  ALLOC  3 .comment      0000002c  00000000  00000000  00000064  2**0                  CONTENTS, READONLY  4 .note.GNU-stack 00000000  00000000  00000000  00000090  2**0                  CONTENTS, READONLY  5 .eh_frame     00000038  00000000  00000000  00000090  2**2                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATASYMBOL TABLE:00000000 l    df *ABS*00000000 main.i00000000 l    d  .text00000000 .text00000000 l    d  .data00000000 .data00000000 l    d  .bss00000000 .bss00000000 l    d  .note.GNU-stack00000000 .note.GNU-stack00000000 l    d  .eh_frame00000000 .eh_frame00000000 l    d  .comment00000000 .comment00000000 g     O .data00000004 a00000004 g     O .data00000004 b00000000 g     F .text00000026 main00000000         *UND*00000000 addDisassembly 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 20             sub    $0x20,%esp   9:8b 15 00 00 00 00    mov    0x0,%edxb: R_386_32b   f:a1 00 00 00 00       mov    0x0,%eax10: R_386_32a  14:89 54 24 04          mov    %edx,0x4(%esp)  18:89 04 24             mov    %eax,(%esp)  1b:e8 fc ff ff ff       call   1c <main+0x1c>1c: R_386_PC32add  20:89 44 24 1c          mov    %eax,0x1c(%esp)  24:c9                   leave    25:c3                   ret    

2.5 链接

ld -m elf_i386 -o main main.o add.o

2.6 相关命令汇总

cpp main.c main.i
cc1 main.i -o main.s
as --32 -o main.o main.s
objdump -dx main.o >main.o.txt

cpp add.c add.i
/usr/lib/gcc/x86_64-linux-gnu/4.8.4/cc1 -m32 add.i -o add.s
as --32 -o add.o add.s
objdump -dx add.o >add.o.txt

链接:
ld -m elf_i386 -o main main.o add.o

备注:cc1命令使用的版本路径
/usr/lib/gcc/x86_64-linux-gnu/4.8.4/ cc1

3 可执行文件分析

3.1 可执行ELF文件空间布局

3.2 可执行文件反编译

objdump -dx main

3.2.1 文件基本信息

main: file format elf32-i386
main
architecture: i386, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x08048094

3.2.2 程序头部表信息

Program Header:
LOAD off 0x00000000 vaddr 0x08048000 paddr 0x08048000 align 212
filesz 0x00000120 memsz 0x00000120 flags r-x
LOAD off 0x00000120 vaddr 0x08049120 paddr 0x08049120 align 2
12
filesz 0x00000008 memsz 0x00000008 flags rw-
STACK off 0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**4
filesz 0x00000000 memsz 0x00000000 flags rw-
说明:
Off:目标文件中的偏移
Vadd/paddr:内存地址
Align:对齐要求
Filesz:目标文件中的段大小
Memsz:内存中的段大小
Flags:运行时访问权限

3.2.3 段信息

Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000033 08048094 08048094 00000094 20
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .eh_frame 00000058 080480c8 080480c8 000000c8 2
2
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .data 00000008 08049120 08049120 00000120 22
CONTENTS, ALLOC, LOAD, DATA
3 .comment 0000002b 00000000 00000000 00000128 2
0
CONTENTS, READONLY

3.2.4 符号表信息

SYMBOL TABLE:
08048094 l d .text 00000000 .text
080480c8 l d .eh_frame 00000000 .eh_frame
08049120 l d .data 00000000 .data
00000000 l d .comment 00000000 .comment
00000000 l df ABS 00000000 main.i
00000000 l df ABS 00000000 add.i
00000000 l df ABS 00000000
08049124 g O .data 00000004 b
080480ba g F .text 0000000d add
00000000 UND 00000000 _start
08049128 g .data 00000000 __bss_start
08048094 g F .text 00000026 main
08049128 g .data 00000000 _edata
08049128 g .data 00000000 _end
08049120 g O .data 00000004 a

3.2.5 反汇编信息

Disassembly of section .text:

08048094 :
8048094: 55 push %ebp
8048095: 89 e5 mov %esp,%ebp
8048097: 83 e4 f0 and $0xfffffff0,%esp
804809a: 83 ec 20 sub $0x20,%esp
804809d: 8b 15 24 91 04 08 mov 0x8049124,%edx
80480a3: a1 20 91 04 08 mov 0x8049120,%eax
80480a8: 89 54 24 04 mov %edx,0x4(%esp)
80480ac: 89 04 24 mov %eax,(%esp)
80480af: e8 06 00 00 00 call 80480ba
80480b4: 89 44 24 1c mov %eax,0x1c(%esp)
80480b8: c9 leave
80480b9: c3 ret

080480ba :
80480ba: 55 push %ebp
80480bb: 89 e5 mov %esp,%ebp
80480bd: 8b 45 0c mov 0xc(%ebp),%eax
80480c0: 8b 55 08 mov 0x8(%ebp),%edx
80480c3: 01 d0 add %edx,%eax
80480c5: 5d pop %ebp
80480c6: c3 ret

4 加载可执行目标文件

4.1 运行时内存映像

5 参考资料

1、《深入理解计算机系统》,【美】Randal E.Bryant,David R.O’Hallaron
, 第3版,2019年3月,机械工业出版社,

(0)

相关推荐