程序的机器级表示

2020-11-04 09:38:48 浏览数 (1)

CSAPP

机器级表示

汇编

  • 两个抽象
    • 硬件 指令集 ISA 的抽象
    • 虚拟内存 大数组
  • 汇编与高级语言的区别
    • 暴露的可操作
      • 程序计数器 rip
      • 条件寄存器
      • 整数寄存器
  • ATT 汇编与 intel 汇编区别
    • intel 省略了 指示大小的后缀
    • Intel省略了 寄存器前的 %
    • Intel 有很多不同的方法 描述内存的位置
    • 多个操作数 Intel 列出的操作数 是相反的

访问信息

  • 不同类型操作数
    • 寄存器
    • 立即数
    • 内存引用
  • 数据传送
    • mov S , D
  • 入栈出栈
    • push
      • sub %rsp; mov xxx (%rsp)
    • pop
      • mov %rsp xxx , add %rsp
    • pic
  • lea
    • load effective addr
      • 加载有效地址
    • lea s , d -> d=&s

控制

  • 条件码寄存器
    • CF 进位标志
    • ZF 零标志
    • SF 符号标志
    • OF 溢出标志
  • 访问条件码
    • 可以依据条件码的某种组合,将一个字节设置成0或1
      • SET 指令
        • setne D -> D=~ZF
    • 可以条件跳转到程序的其他部分
    • 可以有条件的传送数据
  • 跳转指令
    • 无条件跳转
      • jmp
        • 直接跳转
          • 跳转目标是作为指令的一部分编码
        • 间接跳转
          • 跳转目标是从寄存器或内存位置读出
    • 有条件跳转
      • 例子
        • jnz
        • jz
        • jne
      • 条件跳转只能 直接跳转
    • 跳转指令的编码
      • 跳转指令有几种不同的编码,最常用的是 PC相对的
        • PC-relative
          • 地址偏移量编码为 1 2 4字节
          • 指令编码很简洁
          • 目标代码可以不做改变就移到内存不同的位置
      • 绝对地址
        • 4个字节直接指定目标
  • 分支、循环、switch

过程

  • 概念
    • 用指定的一组参数和可选的返回值实现某种功能
  • 转移控制
    • 过程
      • 压栈,设置%rip ; 弹出地址,设置%rip
    • 跳转
      • 直接跳转
      • 间接跳转
  • 传递数据
    • 寄存器传参
      • rdi rsi rdx rcx r8 r9
    • 超过6个参数
      • 栈上传参
  • 分配和回收内存
    • 栈上的局部存储
      • 变量取地址
      • 结构
    • 寄存器局部存储
      • 寄存器保存惯例
        • 被调用者保存寄存器
          • rbp rbx r12~r15
          • %rbp 是栈帧指针,用于标识当前栈帧的起始位置
          • leave 指令来实现两条命令
          • movq %rbp, %rsp
          • popq %rbp
  • 实现基础
    • 运行时栈
      • 过程需要的存储空间超出寄存器大小,在栈上分配的数据称栈帧

结构与数组

  • 数组
    • movl (%rdx , %rcx , 4) , %rax
  • 结构
    • 通过首地址的相对偏移

过程的详细解释

代码语言:javascript复制
void proc(long a1, long*a1p , int a2 , int* a2p, short a3, short* a3p , char a4, char* a4p  )
{
    *a1p  = a1;
    *a2p  = a2;
    *a2p  = a3;
    *a4p  = a4;
}


int main()
{
    long a1 = 0x12345678; 
    long*a1p = &a1;
    
    int a2 = 0x66666666; 
    int* a2p = &a2;

    short a3 = 0x3333; 
    short* a3p = &a3;
    
    char a4 = 0xFE; 
    char* a4p = &a4;
    
    proc( a1 ,a1p , a2, a2p, a3, a3p,a4 , a4p  );
    
    a1 = 0x11112222;
    a2 = 0x66669999;

    return 0;
}

栈描述

代码语言:javascript复制
int main()
{
  400565:   55                      push   %rbp
  400566:   48 89 e5                mov    %rsp,%rbp
  400569:   48 83 ec 40             sub    $0x40,%rsp
    long a1 = 0x12345678; 
  40056d:   48 c7 45 d8 78 56 34    movq   $0x12345678,-0x28(%rbp)
  400574:   12  
    long*a1p = &a1;
  400575:   48 8d 45 d8             lea    -0x28(%rbp),%rax           // 先构造了一些 局部变量
  400579:   48 89 45 f8             mov    %rax,-0x8(%rbp)
    
    int a2 = 0x66666666; 
  40057d:   c7 45 d4 66 66 66 66    movl   $0x66666666,-0x2c(%rbp)
    int* a2p = &a2;
  400584:   48 8d 45 d4             lea    -0x2c(%rbp),%rax
  400588:   48 89 45 f0             mov    %rax,-0x10(%rbp)

    short a3 = 0x3333; 
  40058c:   66 c7 45 d2 33 33       movw   $0x3333,-0x2e(%rbp)
    short* a3p = &a3;
  400592:   48 8d 45 d2             lea    -0x2e(%rbp),%rax
  400596:   48 89 45 e8             mov    %rax,-0x18(%rbp)
    
    char a4 = 0xFE; 
  40059a:   c6 45 d1 fe             movb   $0xfe,-0x2f(%rbp)
    char* a4p = &a4;
  40059e:   48 8d 45 d1             lea    -0x2f(%rbp),%rax
  4005a2:   48 89 45 e0             mov    %rax,-0x20(%rbp)
    
    proc( a1 ,a1p , a2, a2p, a3, a3p,a4 , a4p  );  
  4005a6:   0f b6 45 d1             movzbl -0x2f(%rbp),�x       // 通过寄存器和栈 传参
  4005aa:   0f be f8                movsbl %al,�i
  4005ad:   0f b7 45 d2             movzwl -0x2e(%rbp),�x
  4005b1:   44 0f bf d0             movswl %ax,%r10d
  4005b5:   8b 55 d4                mov    -0x2c(%rbp),�x
  4005b8:   48 8b 45 d8             mov    -0x28(%rbp),%rax
  4005bc:   4c 8b 4d e8             mov    -0x18(%rbp),%r9
  4005c0:   48 8b 4d f0             mov    -0x10(%rbp),%rcx
  4005c4:   48 8b 75 f8             mov    -0x8(%rbp),%rsi
  4005c8:   4c 8b 45 e0             mov    -0x20(%rbp),%r8
  4005cc:   4c 89 44 24 08          mov    %r8,0x8(%rsp)
  4005d1:   89 3c 24                mov    �i,(%rsp)
  4005d4:   45 89 d0                mov    %r10d,%r8d
  4005d7:   48 89 c7                mov    %rax,%rdi
  4005da:   e8 11 ff ff ff          callq  4004f0 <proc>

gdb 调试

代码语言:javascript复制
void proc(long a1, long*a1p , int a2 , int* a2p, short a3, short* a3p , char a4, char* a4p  )
{
  4004f0:   55                      push   %rbp
  4004f1:   48 89 e5                mov    %rsp,%rbp
  4004f4:   48 89 7d f8             mov    %rdi,-0x8(%rbp)
  4004f8:   48 89 75 f0             mov    %rsi,-0x10(%rbp)
  4004fc:   89 55 ec                mov    �x,-0x14(%rbp)
  4004ff:   48 89 4d e0             mov    %rcx,-0x20(%rbp)
  400503:   44 89 c2                mov    %r8d,�x
  400506:   4c 89 4d d8             mov    %r9,-0x28(%rbp)
  40050a:   8b 45 10                mov    0x10(%rbp),�x
  40050d:   66 89 55 e8             mov    %dx,-0x18(%rbp)
  400511:   88 45 d4                mov    %al,-0x2c(%rbp)
    *a1p  = a1;
  400514:   48 8b 45 f0             mov    -0x10(%rbp),%rax       // 寄存器 能传递6个参数
  400518:   48 8b 10                mov    (%rax),%rdx
  40051b:   48 8b 45 f8             mov    -0x8(%rbp),%rax        // 其余的参数可以相对 rbp 获取
  40051f:   48 01 c2                add    %rax,%rdx
  400522:   48 8b 45 f0             mov    -0x10(%rbp),%rax
  400526:   48 89 10                mov    %rdx,(%rax)
    *a2p  = a2;
  400529:   48 8b 45 e0             mov    -0x20(%rbp),%rax
  40052d:   8b 10                   mov    (%rax),�x
  40052f:   8b 45 ec                mov    -0x14(%rbp),�x
  400532:   01 c2                   add    �x,�x
  400534:   48 8b 45 e0             mov    -0x20(%rbp),%rax
  400538:   89 10                   mov    �x,(%rax)

call proc后, 这个过程会push main的调用地址的下一处,在proc里面也会push rbp, 通过打印内存的值,可以看到 rsp上 存储的变量信息, 选用的数字比较有规则,比如 0x12345678 , 0x 66666666 如下图:

0 人点赞