C程序是如何跑起来的01 —— 可执行文件的构成
学习目的
- 程序烧到什么地方?
- 程序加载到内存什么地方?
- 程序如何执行?
一、编译环境搭建
ubuntu 20.04 使用 arm-linux-gnueabihf-gcc 7.5.0。
二、程序源码
main.c:
#include <stdio.h>
#include "calc.h"
int main(int argc, char *argv[])
{
int a, b;
static int local_val = 2;
static int uninit_local_val;
a = add(2, 3);
b = sub(5, 4);
printf("a = %d\n", a);
printf("b = %d\n", b);
return 0;
}
calc.h:
#ifndef _CALC_H_
#define _CALC_H_
int add(int a, int b);
int sub(int a, int b);
#endif
calc.c:
#include "calc.h"
int add(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
编译:
arm-linux-gnueabihf-gcc main.c calc.c
交叉编译生成 a.out 可执行文件,文件类型是 32 位 ARM 平台可执行文件。
三、readelf 工具
readelf 工具由编译器提供,用来列出关于可执行文件的内容的相关信息。
使用格式如下:
Usage: readelf <option(s)> elf-file(s)
(1)查看可执行文件的头部 信息
-h
:用于列出 ELF 文件的头部信息,包括可执行文件运行的平台、软件版本、程序入口地址,以及 program headers、section header 等信息;
(2)查看 section header
-S
:用于列出程序中 section 的头部信息
四、可执行文件的组成结构
一个可执行文件由一系列 section 构成,section 称为段,包括:代码段 text、只读数据段 rodata、数据段 data、bss 段等。
每个 section 用一个section header描述,包括段名、段的类型、段的起始地址、段的偏移、段的大小等。
将可执行文件的所有 section header 集合到一起就是 section header table,使用 readelf 的 -S
参数查看的就是该表。
在程序编译的时候,对 C 语言代码中定义的函数、变量、未初始化的全局变量进行编译分类,放置在不同的段中:
- 普通代码翻译成二进制放到代码段(text)中
- 常量放在只读数据段(rodata)中
- 初始化的全局变量和静态局部变量放在数据段(data)中
BSS 段比较特殊,未初始化的全局变量和静态变量都会放置到 bss 段中,但因为这些变量的值都是 0,没有必要再开辟空间存储,所以在可执行文件中 bss 段是不占用空间的。
但是 BSS 段的大小、起始地址、各个变量的地址信息都会分别保存在 section header table 和符号表 symtab 中,当程序运行的时候,加载器会根据这些信息在内存中紧挨着数据段之后的空间,为 BSS 段开辟一片存储空间,为各个变量分配存储空间。
总而言之:BSS 段在可执行文件中不占用空间,在程序运行的时候才分配对应的空间。
如果在编译时开启了调试选项,则可执行文件中还会有 .debug section,用来保存可执行文件中每一条二进制指令对应的源码位置信息,根据这些信息,GDB 调试器就可以支持源码级的单步调试。
在最后环节,编译器还会在可执行文件中添加一些其它的 section,比如 .init section,这些代码来自 C 语言运行库的一些汇编代码,用来初始化 C 程序所依赖的环境。
参考资料
- 嵌入式 C 语言自我修养 从芯片、编译器到操作系统
相关文章
- 公众号微信平台开发_订阅号 小程序
- 写字机器人程序
- eclipse运行java程序_如何在Eclipse中运行简单的Java程序?「建议收藏」
- 如何在桌面端实现小程序的运行?
- plc梯形图编程入门基础知识_plc简单循环程序梯形图
- 高质量编码--Python开发串口读取程序
- 单片机里的程序是如何运行的?
- 关于手机app或者小程序自动化如何移动滑块
- 微信小程序cover-view、view标签内文字无法自动换行的解决办法
- (四)汇编语言——简单程序
- 不同程序集,名称空间类名和方法签名都一样的方法,如何调用
- 微信社区论坛小程序搭建与安装教程
- 用宝塔面板搭建网址缩短程序Polr教程 上集
- 介绍如何在程序中调用sqlplus命令的方式
- Linux查找特定程序whereis实例详解
- 学习如何使用Linux环境运行Java程序(linux下的java)
- Linux下编译C程序的技术指南(linux如何编译c程序)
- 探究Linux引导程序如何实现计算机启动(linux引导程序)
- 使用 PySimpleGUI 轻松为程序和脚本增加 GUI
- Linux下如何调试PHP程序(linux调试php)
- Linux越界问题解析:如何避免程序崩溃和数据丢失(linux越界)
- 如何在Linux中停止运行Java程序(linux停止java)
- Linux:如何安装新程序(linux 如何安装程序)
- 如何在Linux上运行程序(linux怎么运行)
- tc编译的dos程序和vc编译的win32控制台程序的异同