g++基本用法 objdump 查看输出obj文件

生成一个可执行文件。包括两部分:编译阶段,链接阶段。

  • 编译阶段包括三个步骤。

预处理,编译,汇编  ----> 生成obj文件;

  • 链接阶段包括两个步骤。

        对obj文件的合并,符号表合并后,对符号进行解析,分配虚拟地址;

        对符号进行重定位。

编译阶段的编译最耗时间。是检查语法等功能,生成汇编代码。

1. g++编译过程

  g++在对源程序执行编译工作时,需要经过以下四个步骤:(其中 -o 可以理解为将生成的文件 重命名的作用)

 (1) 预处理:对源程序中的宏定义、包含头文件等进行处理,生成后缀名为.i的文件(使用)

g++ -E hello.cpp -o hello.i

   hello.cpp是需要编译的源文件,-o 选项指定输出的文件名。这里使用-E选项编译生成hello.i 文件

 (2) 转化为汇编文件:使用-S 选项,可以将预处理之后的.i文件转换为目标机器的汇编代码.S文件

g++ -S hello.i  -o  hello.s

  使用该参数可以将.i 文件编译生成.s 文件,输出文件名同样使用-o 选项指定。

(3) 汇编文件->目标文件,即转换为机器代码:使用-c选项

g++ -c hello.s -o hello.o

(4) 链接:将上一步产生的目标文件链接为可执行文件,使用-o参数

静态链接 ld -e main main.o  main 为入口函数,.o文件为需要链接的obj文件。

        以上过程是g++工具编译cpp源程序的具体过程,在实际使用时我们可以不用按照流程一步步编译,可以一步到位将源程序编译为可执行文件,只需要使用如下命令:

g++  hello.cpp -o  hello

2、编译结果与链接结果

以这两个函数为例

sum.cpp
int c = 10;
int sum(int a, int b)
{
    int temp = 0;
    temp = a + b;
    return temp;
}

main.cpp
extern int c;
int sum(init a, int b);
int main()
{
    int a = 10;
    int b = 20;
    int ret = sum(a, b);
    return 0;
}
  • 生成可重定位文件。

g++ -c main.cpp    g++ -c sum.cpp     分别生成了 main.o  sum.o,

利用objdump -t main.o 输出目标文件的符号表。在下面,可以看到符号表中有 哪些段。其中有 *UND* 是 sum 文件中的函数和全局数据。从而得知,符号表是在编译阶段后就有了

main.o:     file format elf64-x86-64

SYMBOL TABLE:
0000000000000000 l    df *ABS*	0000000000000000 main.cpp
0000000000000000 l    d  .text	0000000000000000 .text
0000000000000000 l    d  .data	0000000000000000 .data
0000000000000000 l    d  .bss	0000000000000000 .bss
0000000000000000 l    d  .note.GNU-stack	0000000000000000 .note.GNU-stack
0000000000000000 l    d  .eh_frame	0000000000000000 .eh_frame
0000000000000000 l    d  .comment	0000000000000000 .comment
0000000000000000 g     F .text	000000000000002f main
0000000000000000         *UND*	0000000000000000 _GLOBAL_OFFSET_TABLE_
0000000000000000         *UND*	0000000000000000 _Z3sumii

利用 objdump -S main.o 可以查看 main.o 反汇编的结果。并没有给其他obj文件 符号分配地址。可以看 call sum,其地址为 00 00 00 00   如果想一句一句看汇编的话,则 g++ -c main.cpp -g。再objdump -S main.o

main.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <main>:
   0:	55                   	push   %rbp
   1:	48 89 e5             	mov    %rsp,%rbp
   4:	48 83 ec 10          	sub    $0x10,%rsp
   8:	c7 45 f4 0a 00 00 00 	movl   $0xa,-0xc(%rbp)
   f:	c7 45 f8 14 00 00 00 	movl   $0x14,-0x8(%rbp)
  16:	8b 55 f8             	mov    -0x8(%rbp),%edx
  19:	8b 45 f4             	mov    -0xc(%rbp),%eax
  1c:	89 d6                	mov    %edx,%esi
  1e:	89 c7                	mov    %eax,%edi
  20:	e8 00 00 00 00       	callq  25 <main+0x25> call sum函数,sum函数的地址为0
  25:	89 45 fc             	mov    %eax,-0x4(%rbp)
  28:	b8 00 00 00 00       	mov    $0x0,%eax
  2d:	c9                   	leaveq 
  2e:	c3                   	retq   
  • 静态链接

ld -e main *.o  生成 a.out objdump -S a.out 可以看到符号已经重定位。

a.out:     file format elf64-x86-64


Disassembly of section .text:

00000000004000e8 <main>:
  4000e8:	55                   	push   %rbp
  4000e9:	48 89 e5             	mov    %rsp,%rbp
  4000ec:	48 83 ec 10          	sub    $0x10,%rsp
  4000f0:	c7 45 f4 0a 00 00 00 	movl   $0xa,-0xc(%rbp)
  4000f7:	c7 45 f8 14 00 00 00 	movl   $0x14,-0x8(%rbp)
  4000fe:	8b 55 f8             	mov    -0x8(%rbp),%edx
  400101:	8b 45 f4             	mov    -0xc(%rbp),%eax
  400104:	89 d6                	mov    %edx,%esi
  400106:	89 c7                	mov    %eax,%edi
  400108:	e8 0a 00 00 00       	callq  400117 <_Z3sumii>
  40010d:	89 45 fc             	mov    %eax,-0x4(%rbp)
  400110:	b8 00 00 00 00       	mov    $0x0,%eax
  400115:	c9                   	leaveq 
  400116:	c3                   	retq   

0000000000400117 <_Z3sumii>:
  400117:	55                   	push   %rbp
  400118:	48 89 e5             	mov    %rsp,%rbp
  40011b:	89 7d ec             	mov    %edi,-0x14(%rbp)

 还可以利用 readelf 来查看 obj文件的信息。

  3.g++常用编译选项

 在使用g++工具进行编译时,我们可以附加一些编译选项让编译更加智能,从而方便我们查看编译错误和警告。g++提供了许多有用的编译选项,下面总结一些常用选项:

  -o FILE: 指定输出文件名,在编译为目标代码时,这一选项不是必须的。如果FILE没有指定,缺省文件名是a.out

 -Wall: 允许发出gcc能提供的所有有用的警告,也可以用-W(warning)来标记指定的警告

 -v: 显示在编译过程的每一步中用到的命令 ;

-g: 在可执行程序中包含标准调试信息, 使用该选项生成的可执行文件可以用gdb工具进行调试;

 -L: 库文件依赖选项,该选项用于指定编译的源程序依赖的库文件路径,库文件可以是静态链接库,也可以是动态链接库,linux系统默认的库路径是/usr/lib,如果需要的库文件不在这个路径下就要用-L指定

g++  foo.cpp  -L/home/lib  -lfoo  -o   foo

 -I: 该选项用于指定编译程序时依赖的头文件路径,linux平台默认头文件路径在/usr/include下,如果不在该目录下,则编译时需要使用该选项指定头文件所在路径

gcc  foo.cpp  -I/home/include   -o  foo

 4.编译动态库

  g++除了可以编译源程序生成可执行文件,也可以编译动态链接库,方法如下:

 (1) 分步完成

        gcc -fPIC -c func.cpp -o func.o
        gcc -shared -o libfunc.so func.o

 (2) 一步完成

gcc -fPIC -shared -o libfunc.so func.cpp

 5. make和Makefile

        已经介绍了g++工具在命令行的使用,我们可以使用g++在命令行来对单个或者多个源程序文件进行编译。但是,如果遇到需要同时编译许多文件的情况,g++命令行编译就太麻烦了,这个时候就需要使用make进行自动化编译。我们可以编写make工具的规则文件——Makefile,在该文件中定义一些编译的规则,然后利用make工具自动调用g++进行批量编译,这样可以大大提高效率。

 6、camke 和 CMakeLists.txt

      cmake 与 CMakeLists.txt ,则使更加简单,且跨平台。书写CMakeLists.txt 之后,执行cmake,生成 Makefile 文件,再make。

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
objdump是一个用于查看目标文件、可执行文件和共享库文件的工具。它可以显示这些文件的各个部分的详细信息,包括代码段、数据段、符号表等。然而,objdump本身并不提供合并文件的功能。 如果你想要合并多个目标文件或可执行文件,你可以使用其他工具来完成这个任务,比如ld(链接器)。ld是GNU工具链中的一部分,它可以将多个目标文件链接在一起,生成一个可执行文件或共享库。 下面是一些关于合并文件的常见问题和答案: 1. 如何使用ld来合并多个目标文件? 使用ld命令可以将多个目标文件链接在一起。例如,要将两个目标文件file1.o和file2.o合并成一个可执行文件output,可以使用以下命令: ``` ld -o output file1.o file2.o ``` 2. 如何将多个可执行文件合并成一个可执行文件? 如果你想要将多个可执行文件合并成一个可执行文件,你需要先将这些可执行文件反汇编为目标文件,然后再使用ld进行链接。例如,要将两个可执行文件exec1和exec2合并成一个可执行文件output,可以按照以下步骤进行操作: - 使用objdump将exec1和exec2反汇编为目标文件: ``` objdump -d exec1 > exec1.o objdump -d exec2 > exec2.o ``` - 使用ld将这两个目标文件链接在一起: ``` ld -o output exec1.o exec2.o ``` 3. 是否有其他工具可以用于合并文件? 是的,除了ld之外,还有其他一些工具可以用于合并文件,比如objcopy和ar。objcopy可以用于复制和转换目标文件,而ar可以用于创建、修改和提取归档文件。根据你的具体需求,选择合适的工具进行文件合并操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值