GCC编译过程

二进制文件

​ 计算机文件基本上分为两种:二进制文件和ASCII(也称纯文本文件),图形文件及文字处理程序等计算机程序都属于二进制文件.

​ 可重定位文件:ELF格式的二进制文件(可重定位即可以重新定位内存地址信息)

GCC编译过程(在ubntu18.04环境下完成)

​ 说一下GCC具体的过程(文件是如何变化又经历了什么)

Hello world.c文件——>Hello world.i文件——>Hello world.s文件——>Hello world.o对象文件——>Hello world.exe可执行文件

注:.c文件可以直接转化为.s和.o文件和.exe文件
例如将.c文件直接转化为.s文件所需要的指令为

gcc -S 'Hello world.c' -o 'Hello world.s'

依次经历的事件为:

首先给出一个C语言程序文件
在这里插入图片描述

  • 预处理 从.c文件转变为.i文件

在这里插入图片描述

打开‘Hello world.i’文件(一下为部分截取代码)

# 1 "Hello world.c"
#1 "<built -in>"
#1 "<command-line>"
...
extern int printf(const char *_restrict_format,...);
...
int main()
{
  printf("Hello world");
  return 0;
}

通过观察我们可以得知预处理的一些处理规则;

  • 递归处理”#include“ 预处理指令,将对应文件的内容复制到该指令的位置

  • 删除所有“#define”指令,并且在其被引用的位置递归地展开所有的宏定义

  • 处理所有条件预处理指令:“#if”、“#ifdef”、“#elif”、“#else”、“#endif”等

  • 删除所有注释

  • 添加行号和文件名标识

  • 编译阶段 从.i文件转变为.s文件

在这里插入图片描述

GCC默认使用AT&T格式(大部分Linux内核都是)的汇编语言,添加编译选项“-masm=intel”可以将其指定为我们熟悉的intel格式。编译选项"-fno-asynchrnous-unwind-tables"则用于生成没有cfi宏的汇编指令,以提高可读性。

在这里插入图片描述

打开文件所见内容

值得一提的是,生成的汇编代码中函数printf()被替换成了puts(),这是因为当printf()只有一个参数时,与puts()是十分类似的,与是GCC的优化策略就将其替换以提高性能

  • 汇编阶段 从.s文件转变为.o对象文件

在这里插入图片描述

​ 此时的目标文件’Hello world.o’是一个可重定位文件(Relocatable file),可以使用objdump命令(liunx自带命令不需要安装)来查看其内容

在这里插入图片描述

​ 此时由于还未进行链接,对象文件中符号的虚拟地址无法确定,于是我们看到字符串hello world的地址被设置为0x0000。

  • 链接阶段 将.o文件转变为.exe可执行文件

可分为静态链接和动态链接。GCC链接默认成为动态链接,这一阶段将目标文件及其依赖库进行链接,生成可执行文件,主要包括地址和空间分配、符号绑定和重定位等操作。

在这里插入图片描述

链接操作由链接器(ld.so)完成,结果就得到了hello文件,这是一个静态链接的可执行文件(加了编译选项-static)

同样file 文件 objdump命令 - sd +文件名 -M intel 执行

因为可执行文件含有大量的库文件,没有截取到相应的结果

理论上的结果应该是

call …<链接> 此链接(实际的符号地址)对应一段汇编代码,程序也就可以被加载到内存了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
GCC 是 C/C++ 编译器,不支持直接编译 Java 代码。Java 代码需要先被编译成字节码,然后由 Java 虚拟机(JVM)解释执行或者编译成本地代码执行。 Java 编译器通常使用 javac 命令进行编译。下面是一个简单的编译示例: ``` javac HelloWorld.java ``` 这将会编译名为 HelloWorld.java 的 Java 源代码文件,并生成一个名为 HelloWorld.class 的字节码文件。 如果你想使用 GCC 编译 Java 代码,你需要先将 Java 代码编译成字节码,然后再使用 GCC 编译字节码文件所生成的头文件和源文件。 下面是一个基本的步骤: 1. 使用 javac 命令编译 Java 代码文件: ``` javac HelloWorld.java ``` 2. 使用 javah 命令生成头文件: ``` javah HelloWorld ``` 这将生成一个名为 HelloWorld.h 的头文件。 3. 将头文件和字节码文件一起使用 JNI 编写 C 代码。在 C 代码中,你需要包含 Java 的头文件和 JNI 库,这样就可以调用 Java 方法了。 4. 使用 GCC 编译 C 代码: ``` gcc -c -I/usr/lib/jvm/java-8-openjdk-amd64/include -I/usr/lib/jvm/java-8-openjdk-amd64/include/linux HelloWorld.c ``` 其中,-I 选项指定了 Java 和 JNI 的头文件所在的目录。 5. 使用 GCC 链接 C 代码和 Java 库: ``` gcc -shared -o libHelloWorld.so HelloWorld.o -lc -ljvm ``` 这将生成一个名为 libHelloWorld.so 的共享库,可以在 Java 中使用 System.loadLibrary() 方法加载。 需要注意的是,由于 GCC 不是专为编译 Java 代码而设计的,因此使用 GCC 编译 Java 代码可能会比较麻烦,并且可能会出现一些问题。建议还是使用专门的 Java 编译器 javac 来编译 Java 代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值