CSAPP02:从源程序到进程(一)


前言

内容分两篇完成
(1)程序的编译,汇编,链接:知识包括编译原理,cpu指令集架构(Y86-64),链接。
(2)程序的加载,执行:知识包括操作系统(进程,虚拟内存,文件)


一、编译

编译:将.c高级程序语言转化为.s汇编语言。

1.编译原理

【词法分析】
依照有限自动机的模型,将单词串与标识符对应
【语法分析】
使用“上下文无关文法”将符号表构成抽象语法树,选择合适的方法,如LR,LL方法进行分析
【语义分析】
将语法树与语义相对应,完成类型匹配,转化的工作
【中间代码生成】
将语法树使用顺序的三地址码形式表示
【目标代码生成】
对中间代码进行优化,翻译成汇编指令

2.汇编分析

  • 指令:gcc -s hello.i -o hello.s
  • 内存段:
    【代码段(code segment)】
    .text段:代码段,还保存只读的常量
    【数据段(data segment)】
    .data段:已初始化的全局变量,是静态内存分配
    .rodata段:存放C中的字符串和#define定义的常量
    .bss段:未初始化的全局变量,是静态内存分配
    【栈stack】
    程序运行时内存区,存放局部变量
    【堆heap】
    程序运行时动态分配的内存区

3. 机器级表示

注:机器级编程需要考虑程序计数器PC,寄存器,状态码

  • 基础
    【数据访问】
    寄存器:%rsp(栈指针)
    立即数:$Imm
    内存引用:Imm(rb, ri, s):M[ Imm + rb + ri*s]
    【常用指令】
    数据传送:mov
    栈操作:push, pop
    地址操作:leap
    算术运算:add, sub, mul
    逻辑运算:and, xor, or
  • 控制
    【条件码】
    cmp S1, S2:不改变寄存器,重新设置条件码
    set D
    【跳转指令】
    jmp:无条件跳转
    jop:条件跳转
//条件控制
//存在不确定跳转,常用分支预测填满流水线,损失性能
cmpq %rsi, %rdi
  jge .L1
  PROC2
  ret
.L1:
  PROC1
  ret
//条件传送
//可能存在计算错误
movq %rsi, %rax
subq %rdi, %rax  //y-x
movq %rdi, %rdx
subq %rsi, %rdx  //x-y
cmpq %rsi, %rdi
cmovge %rdx, %rax
ret 
//循环:while, do while, for大同小异
fact_while:
  movl $1, %eax
  jmp .JUDGE
.L1:
  imulq %rdi, %rax
  subq $1, %rdi
.JUDGE:
  cmpq $1, %rdi
  jg .L1
  rep; ret
  • 函数
    栈帧:函数被调用时,创建定长的栈帧管理局部数据和转移控制。
    在这里插入图片描述
//step1: 创建栈帧
push %ebp            ; //基址指针rbp
movl %esp, $ebp      ; 
movl -12(%esp), %esp ; //分配栈帧空间
//step2:code
//...
//step3: 返回调用函数
mov %ebp, %esp	  //返回调用函数的栈指针rsp
pop %ebp          //弹栈
ret               //返回rax

相关指令:call , ret

  1. 数据:数组与结构体

二、汇编

汇编:将.s汇编语言转化为二进制.o目标文件。

1.汇编分析

  1. 指令:as hello.s -o hello.o

  2. 可重定位目标elf格式:readelf -a hello.o > ./elf.txt
    (1)ELF头(ELF header):包含生成该目标文件的系统的字大小和字节顺序、ELF头的大小、目标文件类型、机器类型、节头部表的文件偏移,以及节头部表中条目的大小和数目。
    (2).text: 已编译程序的机器代码
    (3).rodata: 只读数据,比如跳转表等等
    (4).data: 保存已初始化的全局变量和静态变量(全局和局部)
    (5).bss: 保存未初始化的静态变量(全局和局部),以及被初始化为0的全局变量和静态变量(全局和局部)
    (6).symtab: 符号表,存放在程序中定义和引用的函数和变量的符号信息
    注意:不包含局部非静态变量条目,因为该变量是由栈管理的
    (7).rel.text:.text节的重定位信息,可执行目标文件中需要修改的指令地址
    (8).rel.data: .data节的重定位信息,合并后的可执行目标文件中需要修改的指针数据的地址
    (9).debug:调试符号表,其条目是程序中定义的局部变量和类型定义,程序汇总定义和引用的全局变量,以及原始的C源文件
    (10).line: 原始C源程序中的行号和.text节中机器指令之间的映射
    注意:只有以-g选项调用编译器驱动程序,才会出现.debug和.line
    (11).strtab: 字符串表,包括.symtab和.debug节中的符号表,以及节头部中的节名字
    (12)节头部表(Section Header Table):给出不同节的大小和位置等其他信息

  3. 反汇编:objdump -d -r hello.o > dump_hello.txt
    (1)反汇编后数值为16进制,.s中为10进制
    (2)跳转地址为重定位条目,.s中用L1等字段跳转

2.机器指令的执行细节

cpu采用流水线的方式分为五阶段执行:取值,译码,访存,写回,更新
详细内容参考:计算机组成原理与体系结构

三.链接

链接:合并目标文件, 重定位 + 符号解析。

1.链接分析

  1. 可执行ELF文件:
    【对比】
    目标elf: 地址为0,需要重定位,便于链接
    可执行elf: 填充了虚拟地址,无重定位节,增添了库函数信息,便于进程装载
    在这里插入图片描述

  2. 静态链接 和 动态链接
    【静态链接】
    链接器是一个独立程序,将一个或多个库或目标文件(先前由编译器或汇编器生成)链接到一块生成可执行程序。
    这里的库指的是静态链接库,Windows下以.lib为后缀,Linux下以.a为后缀。
    【动态链接】
    链接过程推迟到运行时再进行,在可执行文件装载时或运行时,由操作系统的装载程序加载库。
    这里的库指的是动态链接库,Windows下以.dll为后缀,Linux下以.so为后缀。
    【对比】
    静态链接可执行文件体积较大,包含相同的公共代码,造成浪费。
    动态链接运行时依赖dll模块。

  3. 静态链接步骤
    (1)空间与地址的分配。扫描所有的目标文件,合并相似段,收集当中所有的符号信息。
    (2)符号解析与重定位。调整代码位置。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值