编译过程拆解

  • 预处理处理生成.i文件, .i文件还是源码文件

    • 将所有的宏定义#define展开。
    • 处理#if, #else, #endif等条件编译指令
    • 处理#include, 原地插入文件
    • cpp HelloWorld.c > HelloWorld.i可以这样来进行预编译,cppC preprocessor就是专门做预处理的。或者 通过gcc -E HelloWorld.c -o HelloWorld.i也可以。
  • 经过gcc编译生成.s文件,这个是一个汇编语言的源码文件 可以这样来将.i文件进行编译gcc -S HelloWorld.i -o HelloWorld.s
  • 汇编过程生成.o目标文件 as HelloWorld.s -o HelloWorld.o 这个文件已经不是文本文件了,而是一个ELF文件

ubuntu@cpp:~/Linux-compiler-linker-loader/Demo_Linker_and_Loader/PartI/Demo_3$ file Hello.o

Hello.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped

  • 经过静态链接或动态链接过程生成可执行文件。链接的目的是为了让独立编译的各个模块的源代码能够找到不在自己模块中的符号链接,链接主要就是relocate的过程
yum install glic-static
# 默认动态链接
gcc -o hello HelloWorld.c
# 生成静态链接库
gcc -o hello_st -static HelloWorld.c
# 输出中间过程
gcc -o hello_st -static -verbose HelloWorld.c

Linux目标文件的格式(ELF)

文件类型

elf表示 executable and Linkable Format,可执行可链接的文件。主要有三种文件,通过file命令可以查看/分辨

  • 目标文件 未进行过链接的文件, file显示的就是relocatable

ubuntu@cpp:~/Linux-compiler-linker-loader/Demo_Linker_and_Loader/PartI/Demo_3$ file Hello.o

Hello.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped

  • 可执行文件 最终生成的动态链接或静态链接库

静态态链接库

ubuntu@cpp:~/Linux-compiler-linker-loader/Demo_Linker_and_Loader/PartI/Demo_3$ file hello_st

hello_st: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=e9a2a4bbcef4617eaeae29febf2bb39797016f23, for GNU/Linux 3.2.0, not stripped

动态链接库文件

ubuntu@cpp:~/Linux-compiler-linker-loader/Demo_Linker_and_Loader/PartI/Demo_3$ file hello

hello: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=f1432ef635a38e09c8e1d1a82257236701cdc2d4, for GNU/Linux 3.2.0, not stripped

  • core dump文件 (ubuntu中core dump文件位置 /var/lib/apport/coredump/ 需要设置ulimit -c unlimited)

-46b3-80d7-186db99440fa.3872.184249: ELF 64-bit LSB core file, x86-64, version 1 (SYSV), SVR4-style, from './core', real uid: 1000, effective uid: 1000, real gid: 1000, effective gid: 1000, execfn: './core', platform: 'x86_64'

查看动态链接库所依赖的库文件

ubuntu@cpp:~/Linux-compiler-linker-loader/Demo_Linker_and_Loader/PartI/Demo_3$ ldd hello_st
not a dynamic executable
ubuntu@cpp:~/Linux-compiler-linker-loader/Demo_Linker_and_Loader/PartI/Demo_3$ ldd hello
linux-vdso.so.1 (0x00007ffd1a784000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ffb9ca0b000)
/lib64/ld-linux-x86-64.so.2 (0x00007ffb9cc40000)

Objdump分析ELF各个段存储内容

elf文件的不同段的数据含义:

.bss 通常保存未初始化的全局变量和局部静态变量

.comment 存放gcc中的版本信息

.data段保存初始化的全局变量和局部静态变量,

.rodata段保存只读数据,一般是只读变量和字符串, 常量

.text代码段

更详细的说明可以查看 man elf 或者 /usr/include/elf.h

以以下这个样例来分析下elf文件的内容

#include <stdio.h>

int g_init_var1 = 1;
int g_uninit_var2; void foo(int i)
{
printf("%d",i);
} int main(void)
{
static int var3 = 2;
static int var4; int x = 3;
foo(x);
return 0;
}

编译生成.o文件,通过objdump来分析

objdump -h c_code_obj.o 查看各个段的信息

objdump -d -s c_code_obj.o 查看反汇编的内容

-d, --disassemble Display assembler contents of executable sections

-s, --full-contents Display the full contents of all sections requested



-d 参数将其中的代码段.text进行了反汇编

其中.data段的数据01000000 02000000 和代码中的1 2 是对应的,并且这是一个小端表示法,字节序和使用的平台相关

大端小端

大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,数据从高位往低位放;这和我们的阅读习惯一致。

小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低。

ReadELF分析ELF头信息

readelf -h c_code_obj.o

-h --file-header Display the ELF file header



上面的魔法数字在elf.h中可以找到相应的含义, 这个命令也可以看到这个目标文件的大小端的表示方式

readelf -S c_code_obj.o通过这个和上面 objdump -h查看的内容类似,但是要多一些辅助性的段信息

readelf -p .strtab c_code_obj.o 查看某些段中的string信息

-p --string-dump=<number|name>

readelf -s c_code_obj.o查看符号表定义



Ndx表示符号所在的段,如果符号定义在本目标文件中,那么指示该符号所在段在段表中的下标。UND表示该符号未定义。所以上图中可以看到依赖第三方源码中的printf函数是UND的状态。找不到的就会在链接阶段进行重定位

ELF文件总体结构

根据左图的信息大致可以构建出有图的接口

  1. Start of section headers: 360 对应右图中的Section Table的起始位置 0x168 = 11616+6*16+8 = 360
  2. readelf -S c_code_obj.o可以看到总的有13个段,每个段header的大小是64 所以Section Table的大小就是 0x40 * 13

...

链接

https://www.bilibili.com/video/BV1hv411s7ew

Linux环境下:程序的链接, 装载和库[ELF文件详解]的更多相关文章

  1. 如何查看Linux系统下程序运行时使用的库?

    Linux系统下程序运行会实时的用到相关动态库,某些场景下,比如需要裁剪不必要的动态库时,就需要查看哪些动态库被用到了. 以运行VLC为例. VLC开始运行后,首先查看vlc的PID,比如这次查到的V ...

  2. 解决Linux系统下程序找不到动态库的方法

    思路:一般来说,通过make命令已经将程序依赖的动态库编译出来了,通过make install命令已经将动态库安装到系统的某个路径下.找没找到动态库就看这个路径是否包含在系统默认搜索动态库的路径中,如 ...

  3. windows和linux环境下使用google的glog日志库

    一.概述 glog是google推出的一款轻量级c++开源日志框架,源码在github上,目前最新release版本是v0.3.5. githut地址:https://github.com/googl ...

  4. Linux 环境下程序不间断运行

    一.背景     在linux命令行中执行程序,程序通常会占用当前终端,如果不启动新的终端就没法执行其他操作.简单可以通过'&'将程序放到后台执行,但是这种方法有个问题就是,一旦连接远程服务器 ...

  5. C语言中Linux环境下编译与链接

    编写一个简单的 hello.c 文件,以此为例. 1.编译并链接一个完全包含于一个源文件的C程序. gcc hello.c gcc -Wall hello.c gcc -o hello hello.c ...

  6. 编写第一个Linux环境下程序的编译,下载记录

    跟着韦东山学习Linux: 今天系统系统性的学了代码的编译下载,条记录一下: 一,代码:001_led_on.S,就把下面代码编译后Bin文件下载进2440处理器. /* * 点亮LED1: gpf4 ...

  7. [Python学习] Linux环境下的Python配置,必备库的安装配置

    1.默认Python安装情况 一般情况,Linux会预装Python的,版本较低,比如Ubuntu15的系统一般预装的是Python2.7.10. 使用命令:which python可以查看当前的py ...

  8. Linux环境下利用句柄恢复Oracle误删除的数据文件

    在误删除Oracle的数据文件后,如果未关闭数据库,文件句柄还没有释放,且被删除的数据文件占用的磁盘块未被复写,则可以利用句柄的方式来恢复数据文件.下面模拟恢复过程. (一)环境 OS版本:redha ...

  9. Linux 环境下 MySQ导入和导出MySQL的sql文件

    将服务器上的文件导入或导出还需要使用工具传输到本机中,推荐使用winscp,与xshell搭配使用 1 导入数据库 两种方法 .首先建空数据库 mysql>create database abc ...

  10. Linux下nagios网络监控与/proc/net/tcp文件详解

    问题描述:nagios自带的check_antp太过简约,除了状态统计输出外,什么参数都不提供.在面对不同应用服务器时,报警就成了很大问题. 问题描述:nagios自带的check_antp太过简约, ...

随机推荐

  1. Golang 和Python 几个小时前 几分钟 几天前的处理

    在用golang爬虫的时候 总会遇到 10天前 10分钟前 刚刚这种很影响我们爬取正常事件 所以我写了个方法 来格式化这种事件 golang 版本 package utils import ( &qu ...

  2. ES6 学习笔记(九)Set的基本用法

    1 基本用法 set类似于数组,它的成员是唯一的,当有多个相同的值,只会保留一份. 1.1 创建方法 Set本身是一个构造函数,用来生成Set实例,如: const s = new Set() let ...

  3. 【红队技巧】Windows存储的密码获取

    [红队技巧]Windows存储的密码获取 免责声明: 使用前提 支持版本 利用方式 参考: 免责声明: 本文章仅供学习和研究使用,严禁使用该文章内容对互联网其他应用进行非法操作,若将其用于非法目的,所 ...

  4. 基于SqlSugar的开发框架循序渐进介绍(22)-- Vue3+TypeScript的前端工作流模块中实现统一的表单编辑和表单详情查看处理

    在工作流页面中,除了特定的业务表单信息外,往往也需要同时展示通用申请单的相关信息,因此在页面设计的时候需要使用一些组件化的概念来实现动态的内容展示处理,本篇随笔介绍Vue3+TypeScript+El ...

  5. PyQt5程序打包出错Failed to execute script

    出现这种报错一般有两种可能: 1. 该被引入的资源你没有放到 exe 的相对路径 这种错误一般是你直接引入图片或者图标, 而没有放到 打包后的exe的相对路径 2. 加参数 假设 main.py 为程 ...

  6. 学习ASP.NET Core Blazor编程系列十五——查询

    学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 学习ASP.NET Core Blazor编程系 ...

  7. 软件工程大作业——“你帮我助”软件开发v2.0

    项目简介 在疫情管控期间,很多物资由于信息不对称,不能达成资源的有效分配,尽管这样的事件已经基本不会在新冠疫情的场景中出现,但是开发出一个物品交换的公开信息平台在任何一个社区中都是有必要的,这是构建完 ...

  8. python文件的写入与读出

    Python对文件的处理,新建目录,写入一个txt文件然后读取刚才写入的内容.这里是在windows系统演示,目录用"\".如果在linux系统,区别就是目录的斜杠号要用" ...

  9. 1、debug调试

    Debug断点调试: Debug调试界面图: 利用Debug功能来追踪代码的运行流程,分析与定位异常发生的位置,观察运行中数据的变化. 1.Step Over(F8):进入下一步,如果当前行断点是一个 ...

  10. 有备无患!DBS高性价比方案助力富途证券备份上云

    "某中心受病毒攻击,导致服务中断,线上业务被迫暂停" "某公司员工误操作删库,核心业务数据部分丢失,无法完全找回" "由于服务器断线,某医院信息系统瘫 ...