gcc编译和目标文件

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" 1
int add(int a,int b);
# 2 "main.c" 2
int 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"
	.globl	a
	.data
	.align 4
	.type	a, @object
	.size	a, 4
a:
	.long	1
	.globl	b
	.align 4
	.type	b, @object
	.size	b, 4
b:
	.long	2
	.text
	.globl	main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	subq	$16, %rsp
	movl	b(%rip), %edx
	movl	a(%rip), %eax
	movl	%edx, %esi
	movl	%eax, %edi
	call	add
	movl	%eax, -4(%rbp)
	leave
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.ident	"GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.4) 4.8.4"
	.section	.note.GNU-stack,"",@progbits
2.3.2	add.s
	.file	"add.i"
	.text
	.globl	add
	.type	add, @function
add:
.LFB0:
	.cfi_startproc
	pushl	%ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	movl	%esp, %ebp
	.cfi_def_cfa_register 5
	movl	12(%ebp), %eax
	movl	8(%ebp), %edx
	addl	%edx, %eax
	popl	%ebp
	.cfi_restore 5
	.cfi_def_cfa 4, 4
	ret
	.cfi_endproc
.LFE0:
	.size	add, .-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-i386
main.o
architecture: i386, flags 0x00000011:
HAS_RELOC, HAS_SYMS
start address 0x00000000

Sections:
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, DATA
SYMBOL TABLE:
00000000 l    df *ABS*	00000000 main.i
00000000 l    d  .text	00000000 .text
00000000 l    d  .data	00000000 .data
00000000 l    d  .bss	00000000 .bss
00000000 l    d  .note.GNU-stack	00000000 .note.GNU-stack
00000000 l    d  .eh_frame	00000000 .eh_frame
00000000 l    d  .comment	00000000 .comment
00000000 g     O .data	00000004 a
00000004 g     O .data	00000004 b
00000000 g     F .text	00000026 main
00000000         *UND*	00000000 add



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 20             	sub    $0x20,%esp
   9:	8b 15 00 00 00 00    	mov    0x0,%edx
			b: R_386_32	b
   f:	a1 00 00 00 00       	mov    0x0,%eax
			10: R_386_32	a
  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_PC32	add
  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-i386
main.o
architecture: i386, flags 0x00000011:
HAS_RELOC, HAS_SYMS
start address 0x00000000

Sections:
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, DATA
SYMBOL TABLE:
00000000 l    df *ABS*	00000000 main.i
00000000 l    d  .text	00000000 .text
00000000 l    d  .data	00000000 .data
00000000 l    d  .bss	00000000 .bss
00000000 l    d  .note.GNU-stack	00000000 .note.GNU-stack
00000000 l    d  .eh_frame	00000000 .eh_frame
00000000 l    d  .comment	00000000 .comment
00000000 g     O .data	00000004 a
00000004 g     O .data	00000004 b
00000000 g     F .text	00000026 main
00000000         *UND*	00000000 add



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 20             	sub    $0x20,%esp
   9:	8b 15 00 00 00 00    	mov    0x0,%edx
			b: R_386_32	b
   f:	a1 00 00 00 00       	mov    0x0,%eax
			10: R_386_32	a
  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_PC32	add
  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月,机械工业出版社,

猜你喜欢

转载自blog.csdn.net/skytering/article/details/105877054