csapp学习笔记二----机器级表示

(151) 2024-04-02 10:01:01

机器级表示

这一章主要是要理解汇编代码,以及如何将高级语言转换为汇编语言

程序编码

数据格式

csapp学习笔记二----机器级表示 (https://mushiming.com/)  第1张

一个x86-64中央处理器包含一组16个存储64位值的通用寄存器

有不同的寻址方式
csapp学习笔记二----机器级表示 (https://mushiming.com/)  第2张

数据传送

寄存器传送

寄存器可传送6个整形参数

%rdi %rsi %rdx %rcx %r8 %r9

7~n的参数存放在栈上,对于寄存器不足够存放所有的本地数据,局部变量使用“&”或是数组结构必须存放在内存里

【举例1】

swap_add(&arg1, &arg2)
    
long swap_add(long *xp, long *yp)

调用swap_add,先将arg1,arg2放进栈里,再将参数地址放进寄存器里

subp $16, %rsp	//先将栈指针减6
movq $12, (%rsp)	//向上存放参数
movq $34, 8(%rsp)
leap 8(%rsp), %rsi	//将参数地址放进寄存器里
movq %rsp, %rdi
call swap_add

【举例2】

long call_proc(){ 
   
    long x1 = 1;
    int x2 = 2;
    short x3 = 3;
    char x4 = 4;
    proc(x1, &x1, x2, &x2, x3, &x3, x4, &x4);
    return (x1+x2) * (x3-x4);
}

要为有地址引用的参数分配空间,以及超出寄存器的部分也要存放在内存中,从底向上依次存放参数7~n,局部变量,被保存的寄存器,返回地址。其栈帧分配如下图

%rbx, %rbp, %r12~%r15为被调用者保存寄存器,若应用程序后会用到被调用者保存寄存器,应在汇编开头先push

循环语句翻译方案

循环语句主要是有两种翻译方案,一是跳转到中间,另一个是guarded_do翻译方案

跳转到中间
while(n > 1){ 
   
    result *= n;
    n = n-1;
}
goto test;
loop:
	result *= n;
	n = n-1;
test:
	if(n > 1)
        goto loop;
guarded_do

首先使用条件分支,若初始条件不成立就跳过循环

if(!t)
    goto done;
loop:
	....
    ....
    if(t)
        goto loop;
done: return;

结构体

struct { 
   
    char *a;
    double c;
    char d;
    int h;
    char f;
};

csapp学习笔记二----机器级表示 (https://mushiming.com/)  第3张

注意最后还要填充到32字节满足8字节对齐,这样才能保证p->a,p->c的地址都是8的倍数

结构体节省空间的办法就是重新排列将字节数从大到小排列

变长栈帧分配

long vframe(long n, long idx, long *q){ 
   
    long i;
    long *p[n];
    p[0] = &i;
    for(i = 1; i < n; i++)
        p[i] = q;
    return *p[idx];
}

分配地址空间如下

leaq 22(,%rdi,8), %rax	//8n+22
andq $-16, %rax	//向下约到16的倍数
suq %rax, %rsp	//若n为奇数,%rsp向下增加8n+8,n为偶数为8n+16
leaq 7(%rsp), %rax
shrq $3, %rax	//向上舍入到最近的8的倍数
leaq 0(,%rax,8), %r8
movq %r8, %cx

csapp学习笔记二----机器级表示 (https://mushiming.com/)  第4张

s2-s1为8n+8或8n+16,p为离s2最近的8的倍数

栈攻击c

攻击方式

是输入字符串里包含可执行代码的字节编码,或是用一个指向攻击代码的指针覆盖返回地址

对抗缓冲区溢出的方法
  • 栈随机化

    • 使栈的位置在程序每次运行时都有变化
  • 栈破坏检测

    • 加入栈保护机制,检测缓冲区越界,在栈帧中任何局部缓冲区与栈空间间都保存有一个金丝雀值,在恢复寄存器状态和从函数返回前程序检查这个金丝雀值是否变化,如有变化则说明栈被破坏
  • 限制可执行代码区域

    • 只有保存编译器产生的代码的那部分内存才需要被执行,其他部分可以限制为只允许读

条件码的变化

CF:进位标志

ZF:零标志

SF:符号标志

OF:溢出

AF:辅助进位

PF:奇偶位

OF可以表示带符号数的运算是否超出相应的数值范围

NOT不修改任何的状态标志

INC,DEC不影响CF

leaq,乘法,除法指令不改变条件码

关于汇编的一些细节

  • 生成4字节的指令会把高位4字节也置为0
  • 传送指令的两个操作数都不能指向内存位置
  • 指令寄存器部分的大小必须与指令最后一字符指定的大小匹配
  • movq指令只能以32位立即数为源操作数
  • leaq的目的操作数必须是一个寄存器
  • 一元操作符可以是寄存器,可以是内存位置
  • xorq %rdx, %rdx可以将寄存器清0
  • 除法指令将商存在%rax,将余数存在%rdx中
  • 生成4字节的指令会把高位4字节也置为0
  • 传送指令的两个操作数都不能指向内存位置
  • 指令寄存器部分的大小必须与指令最后一字符指定的大小匹配
  • movq指令只能以32位立即数为源操作数
  • leaq的目的操作数必须是一个寄存器
  • 一元操作符可以是寄存器,可以是内存位置
  • xorq %rdx, %rdx可以将寄存器清0
  • 除法指令将商存在%rax,将余数存在%rdx中
  • cqto将%rdx设置为%rax的符号位
THE END

发表回复