一、程序的编译与链接
从C源代码到可执行文件的生成过程
编译: 由C语言代码生成汇编代码
汇编: 由汇编代码生成机器码
链接 :将多个机器码的目标文件链接成一个可执行文件

C语言→汇编语言→机器码
二、Linux下的可执行文件格式
(1)什么是可执行文件?
广义:文件中的数据是可执行文件
例:
| .out | .exe | .sh | .py |
|---|
狭义:文件中的数据是机器码的文件
例:
| .out | .exe | .dll | .so |
|---|
.out .exe .dl .so
(2)可执行文件的分类
Windows:PE
| 可执行程序 | 动态链接库 | 静态链接库 |
|---|---|---|
| .exe | .dll | .lib |
Linux:ELF
| 可执行程序 | 动态链接库 | 静态链接库 |
|---|---|---|
| .out | .so | .a |
(3)磁盘中的ELF与内存中的ELF
磁盘中的储存方式:节
内存中的储存方式:段

| RW可写 Data段 | RX可读 Code段 |
|---|---|
| .data | .rodata |
| .bss | .text |
| .got | .int |
| .plt | ELF Header |
| Stack | Heap | For Kernel | STACK | HEAP | DATA | CODE |
|---|---|---|---|---|---|---|
| 用来管理函数调用的状态 | 申请动态内存的调用 | 操作系统代码 | 栈段 | 堆段 | 数据段 | 代码段 |
vmmap:查看程序进程的内存空间
注:数据从低地址向高地址写 Heap:是从低往高增长 Stack:是从高往低增长(栈的增长方向是相反的)
三、进程虚拟地址空间

(1)地址编码
地址以字节编码,1Byte=8bits,常以16进制表示
(2)二进制与十六进制转换
1.二进制转十六进制
例:11010110
从右往左每四位一组1101 0110,将二进制转换为十进制在对应为十六进制
1101=1×2³ + 1×2² + 0×2¹ + 1×2⁰ =13=D
0110=0×2³ + 1×2² + 1×2¹ + 0×2⁰=6
11010110=D6
2.十六进制转二进制
例:2AF
将每个十六进制的数转换为对应的四位二进制数,在组合起来
2=0010
A=10=1010
F=15=1111
2AF=0010 1010 1111
(3)虚拟内存
虚拟内存用户空间每个进程一份
虚拟内存内核空间所有进程共享一份
虚拟内存mmap段中的动态链接库仅在物理内存中装载一份
(4)段(segment)与节(section)
| 代码段(Text segment) | 数据段(Data segment) |
|---|---|
| 包含了代码与只读数据 | 包含了可读可写数据 |
| .text 节 | .data 节 |
| .rodata 节 | .dynamic 节 |
| .hash 节 | .got 节 |
| .dynsym 节 | .got.plt 节(保存plt节解析出的函数的实际地址) |
| .dynstr 节 | .bss 节 (只占用内存的空间不占用磁盘的空间) |
| .plt 节(解析动态链接函数的实际地址) | |
| .rel.got 节 |
(5)程序数据是如何在内存中组织的

Data段:放已经初始化的全局变量
Bss段:放未初始化的全局变量
Text段:除了防止代码还放只读数据(.rodata)
Heap段:动态存储区
Stack段:存放局部变量(随着函数执行完被丢弃)
注:x,y是形参,当main函数调用sum函数时才会被用到,只有参数传递的时候才会被使用
32位架构:当main函数调用sum函数时,在创建sum函数的栈帧之前,将x和y的值压栈
64位架构:x,y不会放在虚拟内存中,而是放在寄存器中
(6)大端序与小端序

小端序:低地址存放数据低位、高地址存放数据高位(大部分)

大端序:低地址存放数据高位、高地址存放数据低位(小部分)
注:在C语言中0x00是字符串的结束符,大部分情况数据高位都为0,大端序低地址存放高位数据,数据是从低地址向高地址写,当进行溢出时,从低地址写入遇到0x00就直接结束了,所以小端序比大端序更好利用。
四、程序的装载与进程的执行
(1)进程的执行过程

PC寄存器(Register):存放当前执行指令的地址(process count)
x86 eip x64 rip
(2)寄存器

amd64位寄存器结构
| 名称 | 大小 |
|---|---|
| rax | 8Bytes |
| eax | 4Bytes |
| ax | 2Bytes |
| ah | 1Bytes |
| al | 1Bytes |
部分寄存器的功能
| 名称 | 功能 |
|---|---|
| RSP | 存放当前栈帧的栈顶地址 |
| RBP | 存放当前栈帧的栈底地址 |
| RAX | 通用寄存器存放函数返回值 |
| RIP | 存放当前执行的指令的地址 |
(3)静态链接的程序的执行过程

user mode:用户代码 hernel mode:操作系统代码
(4)动态链接的程序的执行过程

五、x86&amd64汇编简述
(1)常用汇编指令
| MOV | LEA | PUSH | POP | LEAVE | RET |
|---|---|---|---|---|---|
| 把源操作数传送给目标 | 把源操作数的有效地址送给指定的寄存器 | 把目标值压栈,同时SP指针-1字长 | 将栈顶的值弹出至目的存储位置,同时SP指针+1字长 | 在函数返回时,恢复父函数栈帧的指令 | 在函数返回时,控制程序执行流返回父函数的指令 |
(2)两种汇编格式
| intel | AT&T |
|---|---|
| mov eax, 8 | movl $8, %eax |
| mov ebx, 0ffffh | movl $0xffff, %ebx |
| int 80h | int $80 |
| mov eax, [ecx] | movl (%ecx), %eax |
