1 C语言生成可执行二进制文件的具体过程-德赢Vwin官网 网
0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

C语言生成可执行二进制文件的具体过程

小杜的芯片验证日记 来源:数字芯片验证日记 2024-10-21 14:30 次阅读

Hi,我是小杜。SoC验证中会经常使用C语言,所以需要知道C语言生成可执行二进制文件的具体过程以及如何从生成的中间文件读取有用信息。因为小杜是转行做数字IC验证,SoC的知识需要重头开始学,如果错误,还请批评指正。

C语言源码到生成可执行文件的过程通常包括预处理(Preprocessing)编译(Compilation)汇编(Assembly)链接(Linking)等多个步骤,每个步骤都有其特定的任务和产物。下面,小杜通过一个具体的例子详细讲述这个过程,以及如何通过反汇编(Disassembly)来查看汇编、链接产生的不可读二进制目标文件。

C语言源码准备

首先编写3个文件,一个是主程序 main.c,另一个是功能函数 func.c,外加一个头文件 func.h。具体路径为:

project/
│
├──main.c
├── func.c
└── func.h

代码如下:

// main.c
#include 
#include


int main() {
    int result = add(5, 3);
    printf("Result: %d
", result);
    return 0;
}
// func.c
#include "func.h"


int add(int a, int b) {
    return a + b;
}
// func.h
#ifndef FUNC_H
#define FUNC_H


int add(int a, int b);


#endif

分步生成可执行文件

1. 预处理(Preprocessing)

处理器处理 #include、#define 等指令,并生成一个预处理后的文件。可以使用 -E 选项运行预处理器。

gcc-Emain.c-omain.i-I .
gcc-Efunc.c-ofunc.i-I .

main.i 和 func.i 是预处理后的文件,包含展开后的宏和头文件内容。以main.i为例,预处理后的文件可能会非常长,因为所有的宏、头文件都被展开。预处理器在预处理文件中插入了很多#开头的行,提供了文件和行号信息用于调试和错误报告。下面截图展示了main.i文件中的主要部分:

d77efbbada0c87c9d2452c4697b7a758.png

源码中所有的注释都会在预处理阶段被去除。如果源码中有条件编译指令,比如`ifdef,`ifndef,`if 等,预处理器会根据条件和结果保留或删除相应的代码。

预处理文件的用途

调试:通过查看预处理后的文件,可以检查宏和头文件是否正确展开,从而帮助调试编译问题。

了解代码结构:预处理文件展示了代码的最终形态,包括所有的头文件和宏定义,这对理解代码的整体结构很有帮助。

性能优化:分析预处理后的代码,有助于识别和优化编译时间和代码冗余问题。

2.编译(Compilation)

编译器将预处理后的C代码转换为汇编代码。可以使用 -S 选项生成汇编代码。

gcc -s main.i -o main.s -I .
gcc-sfunc.i -o func.s -I .

231418c4da982fbcdf43578c09ee96bf.png

从生成的汇编代码中我们可以看到文件和段定义函数入口和栈帧设置调用add函数调用printf函数以及函数退出

汇编代码可能是调试过程中接触的最底层部分,SoC验证过程中如果CPU卡死,通过记录的寄存器内容、程序计数器(PC)和堆栈指针(SP),找到对应的汇编指令就可以知道CPU卡死的具体位置,这对调试和找出代码bug十分重要。从汇编代码中我们可以得到如下信息:

函数调用和参数传递

通过汇编代码可以看到函数是如何调用的,以及参数是如何传递的。例如,在x86-64架构中,前六个整数参数通过寄存器(如EDI、ESI、EDX等)传递。

栈帧管理

汇编代码展示了栈帧是如何创建和销毁的,尤其是通过 pushq %rbp、movq %rsp, %rbp 和 leave 指令。这有助于理解函数调用过程中栈的变化。

变量和寄存器操作
汇编代码展示了如何使用寄存器和内存操作来实现程序逻辑。例如,通过 movl 指令可以看到如何在寄存器和内存之间传递数据。

调试和优化

通过分析汇编代码,可以发现编译器生成的代码是否高效。例如,可以识别不必要的指令或冗余操作,进而优化代码。

3. 汇编(Assembly)与反汇编(Disassembly)

汇编器将汇编代码转换为机器码,生成目标文件。可以使用 -c 选项生成目标文件。这一步开始生成的二进制目标文件已经不能看了,不过我们还是可以通过反汇编来获取有用信息。

gcc -c main.s -o main.o -I .
gcc-cfunc.s-ofunc.o -I .

fa89308c9cb7370bccd12364056881b3.jpg

main.o 和func.o 是目标文件,包含机器代码、符号表和调试信息,但它们是二进制格式,不像汇编代码那样直接可读。我们可以使用工具来查看分析目标文件,以获取有用的信息,比如使用objdump。

反汇编

通过反汇编可以查看目标文件的机器码、段信息以及符号表。

objdump-dmain.o#反汇编目标文件,显示机器码
objdump-hmain.o#显示目标文件的段信息
objdump -t main.o # 显示符号表

比如反汇编产生机器码(工作中一般不会接触这么深,这里只是举例):

11cf077e50f573983ed7897c960189a5.png

4. 链接(Linking)

链接器将多个目标文件和库文件链接在一起,生成最终的可执行文件。

gccmain.ofunc.o-omyprogram

65949ea6b1f1e83e7bd9af8eff7a256d.png

myprogram 是最终生成的可执行文件。二进制可执行文件不可读,但同样可以使用objdump来查看可执行文件的有用信息,比如:

objdump -f myprogram # 查看可执行文件功能

该输出展示了可执行文件的基本信息,包括文件格式、架构、标志和程序入口信息。

5a89bd9fb1e5320b578b1595d47f5580.png

一步到位的编译和链接

通常我们会直接使用 gcc 命令来一步到位完成整个过程,而不需要手动执行每个步骤:

gccmain.cfunc.-omyprogram

这个命令会自动处理上述所有步骤,并生成最终的可执行文件 myprogram。

总结 让我们来总结一下C语言源码到最终的可执行二进制文件的4个过程分别干了哪些事:

预处理:处理头文件包含和宏定义,生成一个单一的C源文件。

编译:将C源文件转换为汇编代码,这一步会进行语法检查和优化。

汇编:将汇编代码转换为目标文件,目标文件是二进制格式的机器码,但还不是完整的可执行程序。

链接:将多个目标文件和库文件链接在一起,解决符号引用问题(如函数和变量的定义和声明),生成最终的可执行文件。

感谢你看到这里。项目工作中,其实工具链建立好之后一般也就不会去关注这些过程了,写完C代码走脚本流程即可,但如果出现bug,了解这一过程对解决bug就很重要了!

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表德赢Vwin官网 网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 二进制
    +关注

    关注

    2

    文章

    795

    浏览量

    41643
  • C语言
    +关注

    关注

    180

    文章

    7604

    浏览量

    136676
  • 函数
    +关注

    关注

    3

    文章

    4327

    浏览量

    62567
  • 预处理
    +关注

    关注

    0

    文章

    33

    浏览量

    10478

原文标题:【SoC】C code如何生成二进制可执行文件?实例详解

文章出处:【微信号:小杜的芯片验证日记,微信公众号:小杜的芯片验证日记】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    不同机器上生成不同的二进制文件

    模型 - 长堆栈(+ modsl0)我们的目标可执行文件是* .s19格式。但是,当我们构建我们的软件时,它会在不同的机器上生成不同的二进制文件!所有设置都相同,并且正在使用相同的工作
    发表于 11-16 10:27

    一个源文件生成二进制可执行文件的步骤

    = var_value3 funcmainvim filename.c=> srcgcc 编译器filename.c => a.out一个源文件生成
    发表于 10-27 07:04

    二进制

    二进制   二进制与十进制的区别在于数码的个数和进位规律有很大的区别,顾名思义,二进制的计数规律为逢二进一,是以2为基数的计数体制。10这
    发表于 04-06 23:48 8195次阅读
    <b class='flag-5'>二进制</b>

    C语言入门教程-二进制文件

    二进制文件 二进制文件非常类似于结构体数组,只不过这些结构体被保存在一个磁盘文件而非内存数组中。因为是使用磁盘保存
    发表于 07-29 14:24 1936次阅读

    二进制编码和二进制数据

    二进制编码和二进制数据   二进制编码是计算机内使用最多的码制,它只使用两个基本符号"0"和"1",并且通过由这两个符号组成的
    发表于 10-13 16:22 4781次阅读

    二进制电平,什么是二进制电平

    二进制电平,什么是二进制电平 在二进制数字通信系统中,每个码元或每个符号只能是“1”和“0”两个状态之一。若将每个码元可能取的状态增
    发表于 03-17 16:51 2357次阅读

    具有X86到ARM二进制翻译和执行功能的SoC系统设计

      二进制翻译是一种直接翻译可执行二进制程序的技术,能够把一种处理器上的二进制程序翻译到另外一种处理器上执行。它使得不同处理器之间的
    发表于 09-07 10:22 2159次阅读
    具有X86到ARM<b class='flag-5'>二进制</b>翻译和<b class='flag-5'>执行</b>功能的SoC系统设计

    二进制加法程序【C语言版】

    二进制加法程序【C语言版】二进制加法程序【C语言版】二进制
    发表于 12-29 11:03 0次下载

    二进制加法程序【C语言+汇编版】

    二进制加法程序【C语言+汇编版】,多种集合,符合同时爱好C语言+汇编的学习者的胃口。
    发表于 01-06 11:10 0次下载

    C语言教程之十进制转换为二进制

    C语言教程之十进制转换为二进制,很好的C语言资料,快来学习吧。
    发表于 04-22 11:06 0次下载

    C语言编程二进制位操作符

    C语言编程二进制位操作符
    发表于 03-30 14:09 6次下载

    Visual-C#数据库存取二进制字段数据

    现代的数据库不仅要存放数值和字符等数据,还要存放一些二进制类型的文件,常见的如图片文件、动态连接库、可执行文件等。对于数值和字符这些普通数据类型,利用上一章中介绍的编辑记录的方法是完全
    发表于 04-03 15:12 14次下载

    C语言程序内存布局该关注哪些内容

    C语言代码(文本文件)形成可执行程序(二进制文件),需要经过编译-汇编-连接三个阶段。编译
    发表于 05-07 08:03 930次阅读
    <b class='flag-5'>C</b><b class='flag-5'>语言</b>程序内存布局该关注哪些内容

    C语言程序运行流程包含哪些环节

    C语言并不能直接被计算机所理解,需要将C语言转变成可执行代码,即二进制代码。在
    发表于 11-07 15:05 1.3w次阅读

    在Linux上分析二进制文件的10种方法

    这将是你进行二进制分析的起点。我们每天都在与文件打交道,并非所有的文件都是可执行类型,除此之外还有各种各样的文件类型。在你开始之前,你需要了
    的头像 发表于 06-18 17:32 3146次阅读