首页 > 系统相关 >Linux环境下:程序的链接, 装载和库[ELF文件详解]

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

时间:2023-02-04 19:34:49浏览次数:64  
标签:文件 Demo ELF HelloWorld 详解 64 Linux

编译过程拆解

image.png

  • 预处理处理生成.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 查看各个段的信息
image.png

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
objdump_d_s.jpg
-d 参数将其中的代码段.text进行了反汇编
其中.data段的数据01000000 02000000 和代码中的1 2 是对应的,并且这是一个小端表示法,字节序和使用的平台相关

大端小端

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

ReadELF分析ELF头信息

readelf -h c_code_obj.o
-h --file-header Display the ELF file header
image.png
上面的魔法数字在elf.h中可以找到相应的含义, 这个命令也可以看到这个目标文件的大小端的表示方式
readelf -S c_code_obj.o通过这个和上面 objdump -h查看的内容类似,但是要多一些辅助性的段信息
readelf -p .strtab c_code_obj.o 查看某些段中的string信息
-p --string-dump=<number|name>
image.png

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

ELF文件总体结构

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

  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

标签:文件,Demo,ELF,HelloWorld,详解,64,Linux
From: https://www.cnblogs.com/Aitozi/p/17092194.html

相关文章

  • Linux文件系统
    Linux文件系统......
  • Linux的起源
    Linux的起源......
  • Linux之LVM管理 pvcreate,vgcreate,lvcreate命令
    一、逻辑卷管理(LVM)概念逻辑卷和逻辑卷管理有助于更加轻松地管理磁盘空间。如果托管逻辑卷的文件系统需要更多空间可以将其卷组中的可用空间分配给逻辑卷,并且可以调整文件......
  • LSA 1 详解
    <r3>displayospflsdbrouterself-originateOSPFProcess1withRouterID3.3.3.3Area:0.0.0.0LinkStateDatabaseType:RouterLsid:3.3......
  • SpringBoot整合JDBC详解
    SpringBoot整合JDBC@​​TOC​​前言对于数据访问层,无论是关系型数据库(SQL)还是NOSQL(非关系型数据库),SpringBoot的底层都是采用SpringData的方式来进行统一处理。SpringData其......
  • Python中strip()、lstrip()、rstrip()用法详解
    Python中有三个去除头尾字符、空白符的函数,它们依次为:strip:用来去除头尾字符、空白符(包括\n、\r、\t、'',即:换行、回车、制表符、空格)lstrip:用来去除开头字符、......
  • linux中小文件传输rz,sz
    linux中小文件传输rz,szrz输入rz从windows中弹出窗口选择文件传输到linux服务器当前目录sz输入sz加文件名传输到windows,弹出窗口选择目录存储rz,sz安装如果提示找......
  • linux 文件压缩
    linux文件压缩打包成tar.gz格式压缩包#tar-zcvfrenwolesshel.tar.gz/renwolesshel解压tar.gz格式压缩包#tarzxvfrenwolesshel.tar.gz打包成tar.bz2格式压缩......
  • Linux基础
    linux发行版:DebianubuntuRedhatcentosLinux内核从应用角度来看,分为用户空间和内核空间。Linux内核分为5个系统:进程调度、内存管理、虚拟文件系统、网络接口、进程间......
  • [linux] 进程相关概念理解
    @​​TOC​1.什么是进程假设在一个文件中写代码,并生成一个可执行程序在磁盘中,可执行程序本质也是一个二进制文件文件=内容+属性内容即自己写的代码和数据属性即创建时间......