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函数的地址,也就是程序开始时的虚拟地址。

相关推荐
cui_ruicheng3 小时前
Linux网络编程(三):Socket编程预备知识
linux·服务器·网络
小此方3 小时前
Re:Linux系统篇(十六) 进程篇 · 一:深入理解操作系统:从软硬件架构到“先描述,再组织”的管理哲学
linux·驱动开发·硬件架构
Shadow(⊙o⊙)3 小时前
进程分析2.0——进程退出、进程等待-Linux重要经典模块
linux·运维·服务器·开发语言·c++·学习
pengyi8710154 小时前
高匿代理核心原理详解,隐藏真实IP实现无痕网络访问
linux·运维·服务器·网络·tcp/ip
Irissgwe4 小时前
九、Linux信号机制(一)
linux·信号处理·信号·进程信号·信号的产生
皮卡蛋炒饭.4 小时前
数据链路层相关学习
linux·数据链路层
Benszen4 小时前
云计算基础-1: VMware落地部署CentOS 7
linux·centos·云计算
JackSparrow4144 小时前
彻底理解Java NIO(二)C语言实现 I/O多路复用+Reactor模式 服务器详解
java·linux·c语言·后端·nio·reactor模式
feng_you_ying_li4 小时前
linux之库的原理,动态库(3)
linux