<编译理解 一>目标文件是什么样的

1.目标文件是什么?

  • 从hello world讲起

"hello world"是每个程序员的必经之路,在linux下开发,我们编译代码只需要使用如下命令,就能打印出hello world;

$gcc hello.c
$./a.out

但是事实上,上述过程可以被分解为4个步骤,预处理、编译、汇编和链接;

$gcc --help
-E preprocess only;do not compile, assemble or link
-S compile only, do not assemble or link
-c compile andn assemble, but do not link

上述4个步骤不过多描述,这个在网上资料都很多

  • 汇编是什么

汇编做的事情实际上是汇编器将汇编代码转换成机器代码

  • 目标文件定义

经过预处理、编译、汇编过程所生成的文件称为目标文件;
从广义上来说,由于可执行文件与目标文件的格式基本一致,所以可执行文件也可以被认为是目标文件;

2.目标文件分类

ELF文件类型 说明 实例
可重定位文件 这类文件包含代码和数据段,可被用来链接成可执行文件或者共享目标文件 linux下的.o/.a以及windows下的.obj文件
可执行文件 可以直接执行,代表就是ELF可执行文件 windows下的.exe,linux下的a.out
共享目标文件 包含了代码和数据,可以在以下两种情况下使用,1.链接器可用这种文件跟其他的可重定位文件链接,产生新的目标文件;2.动态链接器可以将将共享目标文件和其他可执行文件结合,作为进程的一部分来运行 linxu下的.so 以及windows下的.dll

3.使用工具分析目标文件

  • readelf工具

    • display information about the contents of ELF format file
    • -S选项, display the sections' header,(目标文件的各种不同的信息用section来存储,例如.text段、.data段、.bss段等等)
    • -h选项,展示ELF文件的头文件的信息
  • objdump工具

    • display information from object
    • -D选项,反汇编出所有section
  • nm工具

    • list symbols in files

4.链接的接口——符号

链接的本质是把多个不同的目标文件相互粘连在一起,在链接中我们将函数和变量统称为符号(symbol),函数名或变量名被称为符号名(symbol name)

  • c和c++的兼容

    • c++是支持函数重载的,c是不支持的,关键底层原因在于编译器对这两者做处理是有一定差异的,c处理时将会将一个函数的符号变成_函数,例如hello(void)会变成_hello,而c++会把参数也带进去,变成hellov,因此c++支持重载是因为他的函数参数是可以变化的,编译的时候不会报错
    • 了解原因之后,就会明白c/c++混合编程只需要将一些需要的部分用c的编译器来处理就行,加上extern C

code example:

//hello.c
void hello(void)
{
    printf("hello!\n");
}

//hello.h
#ifdef __cplusplus
extern "C" {
#endif

void hello(void);

#ifdef __cplusplus
}
#endif

//main.cpp
#include "hello.h"
int main(void)
{
    hello();
    return 0;
}

$gcc -c hello.c
$nm hello.o
.....能看到hello的符号是_hello
$g++ -c main.cpp
$nm main.o
看到hello的符号还是_hello,如果在hello.h中将extern C去掉,则发现 nm main.o中的符号是hellov,就会报错

你可能感兴趣的:(编译原理)