liunx之库的原理,核心是静态库(2)

1.对符号表的更进一步说明

首先是两段代码

test.c:

复制代码
#include<stdio.h>
void func()
{
    printf("fuck zsr\n");
    return 0;
}

code.c:

复制代码
#include<stdio.h>
void func();

int main()
{
    func();
    return 0;
}

对test.o进行readelf -s 测试有

cpp 复制代码
ubuntu@VM-0-2-ubuntu:~/test$ readelf -s test.o

Symbol table '.symtab' contains 6 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS test.c
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1 .text
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    5 .rodata
     4: 0000000000000000    26 FUNC    GLOBAL DEFAULT    1 func
     5: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND puts

能发现printf的底层就是puts,有些函数的Ndx是UND,即未定义状态。链接时的操作就是每个文件拿自己未定义的函数去其他文件中进行匹配。

当Ndx为一个准确的值时,代表的意思是其处于的第几个section中。

分别对.o和.exe进行objump -d 操作,能发现曾经未被初始化地址的地方已经初始化了

复制代码
ubuntu@VM-0-2-ubuntu:~/test$ objdump -d test.o

test.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <func>:
   0:	f3 0f 1e fa          	endbr64
   4:	55                   	push   %rbp
   5:	48 89 e5             	mov    %rsp,%rbp
   8:	48 8d 05 00 00 00 00 	lea    0x0(%rip),%rax        # f <func+0xf>
   f:	48 89 c7             	mov    %rax,%rdi
  12:	e8 00 00 00 00       	call   17 <func+0x17>
  17:	90                   	nop
  18:	5d                   	pop    %rbp
  19:	c3                   	ret
ubuntu@VM-0-2-ubuntu:~/test$ objdump -d test
//..
0000000000001162 <func>:
    1162:	f3 0f 1e fa          	endbr64
    1166:	55                   	push   %rbp
    1167:	48 89 e5             	mov    %rsp,%rbp
    116a:	48 8d 05 93 0e 00 00 	lea    0xe93(%rip),%rax        # 2004 <_IO_stdin_used+0x4>
    1171:	48 89 c7             	mov    %rax,%rdi
    1174:	e8 d7 fe ff ff       	call   1050 <puts@plt>//e8能说明与上面是同一个函数,这里
//成功初始化了地址
    1179:	90                   	nop
    117a:	5d                   	pop    %rbp
    117b:	c3                   	ret
//..

地址重定位:链接过程中对.o中的外部符号的地址进行更新(这也就是.o文件名:可重定位目标文件的由来),直接意思就是该文件的内部符号地址可被修改

2.EIF加载

一个.exe,即使没有被加载到内存当中,其也是依旧有地址的。

原因:

(1)EIF的每一个区间都是由其自己的起始地址的(甚至于EIF相对于磁盘整体也是有自己的起始地址的),里面的所有成员的存储位置都是通过该区域的起始地址+偏移量记录的,这种起始地址+偏移量存储地址的方式叫逻辑地址,在进程的mm_struct中寻找变量或函数地址的方式就是通过逻辑地址来调用访问的。

(2)其实从OS看来,整个.exe其实就是一个segment(也就是说OS将一个.exe视为一个整体),对于这个segment而言的起始地址其实为0,也就是说真实情况下EIF的每个成员的地址其实就是偏移量。

(3)EIF编址从0开始编,但不代表要从0为开始用,从某一位开始到最后依次递增编址,这种编址方式叫平坦模式编址(虽然连续,但其实每个区间的地址编号之间不一定连续)

(4)其实磁盘上的EIF得编址就是进程中虚拟地址得编制方式(其实应该说虚拟地址得初始化其实就是EIF编址得数据)

(5)由于磁盘加载进内存与编译器有关,而虚拟地址得形成与OS有关,因此可以说虚拟地址即影响着OS得编制方式,也影响着编译器的编制方式。

(6)说白了内存和磁盘都是采用得平坦模式编址,只是在内存和磁盘中的叫法不同。磁盘中叫其逻辑地址,内存中叫其虚拟地址。故也可以推测进程中的mm_struct和vm_area_struct的数据的初始化其实就是用的EIF中的逻辑地址的数据。

3.EIF中的逻辑地址

所以合并完后是要对整体的section地址进行重新编址的。

总结静态链接的操作

合并.o,重新编址,更新函数地址.

(1).exe在磁盘中存的就是指令汇编语言的二进制机器码。

(2).exe的数据会直接加载到内存中,然后通过内存中每个区间的数据就可以直接初始化到mm_struct中了。

(3)每一行代码都是真实加载到物理内存中的,所以每一行代码在内存中也会有一个真实地址(真实地址与虚拟地址的值增长方向相同),因此一个指令就有两个地址,页表就可以将两个地址加载在页表的两边形成映射关系了。

4.CPU找到.exe的起始物理地址的过程

EIF header中有一个成员Entry point address存储着该.exe的起始虚拟地址该成员在.exe加载进内存是会将其存储的值加载到CPU中一个叫EIP的寄存器中(当CPU指向一个进程时,CR3指向该进程的页表,MMU是用与寻址的),因此CPU能通过EIP和MMU找到EIP指向的真实地址,并将对应的指令加载到寄存器中。

因此进入CPU的地址只是虚拟地址,(EIP+MMU转换找到真实地址就直接去找指令了,并不会返回给CPU),所以CPU并不知道真实地址的存在,其看待内存中的.exe和磁盘中的内容是一模一样的。

不同的segment分别映射为一个vm_area_struct,一个vm_area_struct对应虚拟地址的一个区间,因此不同虚拟地址的区分本质就是不同的segment而已。

总结:

进程先形成PCB,mm_struct,vm_area_struct和页表,通过struct file,找struct path,再找struct inode,最后找到数据块,之后加载磁盘的数据进内存,并用于初始化mm_struct,最后构建页表的映射关系。

EIF中存的地址其实就是_start函数的地址,也就是程序开始时的虚拟地址。

相关推荐
垆边人似月.19 分钟前
RDMA 文件传输踩坑(四):从固定延时改造为 READY/ACK 协议
linux·服务器·网络
水饺编程21 分钟前
第2章:Linux 基础,制作【.tar.xz】压缩包文件
linux·c语言·汇编
阿里云基础软件38 分钟前
Agent 任务提速 10.71%,内存占用降低 21.60%|Alibaba Cloud Linux 4 重大发布
java·linux·人工智能·操作系统·agent
m0_743697591 小时前
DNS的反向域名的相关问题
linux
Android系统攻城狮2 小时前
Linux FFmpeg深度解析之avcodec_parameters_from_context调用流程与实战(十六)
linux·运维·ffmpeg·音视频进阶·ffmpeg音视频·车载音视频进阶
思想觉悟2 小时前
SEAndroid实战
android·linux·c++
前进吧-程序员3 小时前
C++20 协程实战:手写 Task、单线程调度器与 awaiter 的三个钩子
linux
Android系统攻城狮3 小时前
Linux FFmpeg深度解析之avcodec_alloc_context3调用流程与实战(十四)
linux·运维·ffmpeg·车载音视频·音视频进阶·ffmpeg音视频进阶
自由彩虹3 小时前
靶场通关15--bossplayersctf
linux·服务器·网络·安全·web安全·网络安全
叼烟扛炮3 小时前
Linux 学习笔记(四十五):Web 安全基石——Cookie、Session 与 HTTPS 原理解析
linux·前端·网络·笔记·学习·tcp/ip·安全