4.3 机器级代码
字数
750 字
阅读时间
4 分钟
一、循环语句的机器级表示
1. loop指令
扩展:loopx 指令 --- 如:loopnz,loopz
- loopnz --- 当 ecx != 0 && ZF == 0 时,继续循环
- loopz --- 当 ecx != 0 && ZF == 1 时,继续循环
- ZF == 1 --> 运算结果为 0
二、过程调用(函数调用)的机器级表示
- 函数的栈帧(Stack Frame):保存函数大括号内(C语言)定义的局部变量、保存函数调用相关信息
1. 如何访问栈帧?
TIP
在x86中,默认以4字节为栈的操作单位,包括push、pop等操作 栈底在高地址,栈顶在低地址,画栈的示意图时,需要从上往下分别画栈底和栈顶;故若是要进栈,则需要将栈顶寄存器esp-4(此处的4指的是4字节)
方法一:
C
push dog // 先让esp减4,再将dog压入栈
pop horse // 先让栈顶元素出栈,将该出栈元素写入horse地址,再让esp加4
// 注:dog 可以是立即数、寄存器、主存地址
// 注:horse 可以是寄存器、主存地址
// 在Intel格式汇编中,若是主存地址,记得加左右括号 "[" "]"
方法二: mov 指令,结合esp、ebp指针访问栈帧数据 注:可以用减法/加法指令,即:sub/add指令修改栈顶指针esp的值,以模仿push、pop的进出栈操作
TIP
ebp:指向当前栈帧的“底部” esp:指向当前栈帧的“顶部”
2. 一个函数的汇编代码框架(结合栈帧切换相关内容来理解)
保存上一层函数栈帧,设置当前函数栈帧:enter指令
恢复上一层函数的栈帧:leave指令
3. 一个栈帧内可能包含的内容
C
int caller(){
int temp1 = 125;
int temp2 = 80;
int sum = add(temp1,temp2);
return sum;
}
int add(int x, int y)
{
return x+y;
}
栈帧示意图:
通常将局部变量集中存储在栈帧底部区域 如:由示意图可见,C语言中局部变量越靠前定义,则越靠近栈顶(低地址)。也就是说,越靠后定义的局部变量,就越靠近栈底(高地址) 将调用参数存储在栈帧顶部区域,越靠前的参数越靠近栈顶(低地址)
- 栈帧最底部一定是上一层栈帧基址(ebp旧值)
- 栈帧最顶部一定是返回地址(当前函数的栈顶除外)
gcc编译器将每个栈帧大小设置为16B的整数倍(当前函数的栈帧除外)
- 栈帧具体数据内容分布: