欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

学海拾遗:汇编语言实验

程序员文章站 2022-06-08 19:13:55
...

学海拾遗:汇编语言实验

1.简单汇编指令回顾

指令 解释 说明
movl %eax, %edx edx = eax register mode
movl $0x123, %edx edx = 0x123 immediate
movl 0x123, %edx edx = *(int32_t*)0x123 direct
movl (%ebp), %edx edx = *(int32_t*)ebp indirect
movl 4(%ebp), %edx edx = *(int32_t*)(ebp+4) displaced

b, w, l, q分别代表8位,16位, 32位, 64位

寄存器模式:以%开头的寄存器标示符

立即数:以$开头的数值

直接寻址:直接访问一个指定的内存地址的数据

间接寻址:将寄存器的值作为一个内存地址来访问内存

变址寻址:在间接寻址之时改变寄存器的数值

Example instruction

函数调用堆栈是理解C代码在CPU上执行的关键

pushl %eax

​ subl $4, %esp

​ movl %eax, (%esp)


popl %eax

​ movl (%esp), %eax

​ addl $4, %esp


call 0x12345

​ pushl %eip(*)

​ movl $0x12345, %eip(*)

(*)表示eip寄存器不能被直接修改, 只能通过特殊指令间接修改

call指令:

  1. 将eip中的下一条指令的地址A保存在栈顶

  2. 设置eip指向被调用程序代码开始处


ret

​ popl %eip(*)


enter

​ pushl %ebp

​ movl %esp, %ebp


leave

​ movl %ebp, %esp

​ popl %ebp

2. 相关寄存器

计算机三大法宝:存储程序计算机、函数调用堆栈和中断机制

堆栈: C语言程序运行时必须的一个记录调用路径和参数的空间

  • 函数调用框架

  • 传递参数

  • 保存返回地址

  • 提供局部变量空间

C语言编译器对堆栈的使用有一套的规则

了解堆栈存在的目的和编译器对堆栈的使用的规则是理解操作系统一些关键性代码的基础

堆栈相关的寄存器

  • esp, 堆栈指针(Stack pointer)
  • ebp, 基址指针 (base pointer)

堆栈操作

  • push 栈顶地址减少4个字节, 32位
  • pop 栈顶地址增加4个字节

ebp在C语言中用作记录当前函数调用基址

其他关键寄存器

cs: eip: 总是指向下一条的指令地址

  • 顺序执行:总是指向地址连续的下一条指令
  • 跳转/分支:执行这样的指令的时候,cs:eip的值会根据程序的需要被修改
  • call:将当前cs:eip的值压入栈顶,cs: eip指向被调用函数的入口地址
  • ret: 从栈顶弹出原来保存在这里的cs:eip的值,放入cs:eip中

中断机制

3.C语言源码

// main.c
#include <stdio.h>
int g(int x)
{
	return x+5;
}
int f(int x)
{
	return g(x);
}
int main(void)
{
	return f(8) + 10;
}

4.汇编代码

gcc -S main.c -o main.s -m32
-m32编译选项报错时,Ubuntu下执行sudo apt-get install libc6
打开main.s文件删除所有以点开头的内容,剩下来的就纯汇编代码

aaa@qq.com:~/ProC$ gcc -S main.c -o main.s -m32
In file included from /usr/include/stdio.h:27:0,
                 from main.c:1:
/usr/include/features.h:367:25: fatal error: sys/cdefs.h: 没有那个文件或目录
compilation terminated.
aaa@qq.com:~/ProC$ sudo apt-get install libc6

g:
	pushl	%ebp
	movl	%esp, %ebp
	movl	8(%ebp), %eax
	addl	$5, %eax
	popl	%ebp
	ret
f:
	pushl	%ebp
	movl	%esp, %ebp
	pushl	8(%ebp)
	call	g
	addl	$4, %esp
	leave
	ret
main:
	pushl	%ebp
	movl	%esp, %ebp
	pushl	$8
	call	f
	addl	$4, %esp
	addl	$10, %eax
	leave
	ret

函数的返回值默认使用eax寄存器存储返回给上一级函数

call f ==> pushl eip; movl f eip


具体执行过程见下图:

学海拾遗:汇编语言实验
学海拾遗:汇编语言实验
学海拾遗:汇编语言实验