X86汇编基础

RISC(精简指令集)指令数量少、功能简单、一般长度固定编译器实现复杂,CISC(夏杂指令集) 指令数目庞大、复夏杂、指令长度不固定。

汇编基本格式

Intel格式:mov eax, 5      分别是指令助记符、目标操作数、源操作数     window英特尔比较多
AT&T格式: movl $5 %eax    分别是指令助记符、源操作数、目标操作数     Linux、Unix比较多

操作数可以是立即数也可以是一个寄存器的值

mov eax, 5(源操作数是立即数5,目标操作数是寄存器eax,这条指令表示将5赋值给eax寄存器)

操作数也可以是某个内存地址的值

mov eax, dword ptr[exb]
mov byte ptr[esp+8], 5
mov word ptr[eax] 1234h 
将EBX寄存器的值作为一个地址,将这个地址内的数据赋值给EAX寄存器
dword ptr
表示使用指针间接寻址

字节(byte)、字(word)两个字节、双字(dword)两个字、四字(qword)。

常用汇编指令

数学运算

加法:add 减法: sub 乘法:mul / imul 除法:div / idiv

add eax, 5
​
eax = eax + 5;
给eax寄存器的值加5(立即数),同时eax也是运算后保存结果的地方
add eax, ebx
​
eax = eax + ebx;
给eax寄存器的值加一个数后保存在ebx寄存器中
sub esp, 8
​
esp = esp - 8;
esp寄存器的值减去8,esp寄存器指向栈顶减去8相当于把栈顶的位置向下移动8个字节
mul ebx
(eax = eax*ebx;)    
​
iuml eax, dword ptr[ebx] 
(eax = eax**ebx;)
带i前缀的是有符号数的整数运算,没有i前缀的是无符号数的整数运算
div ebx		
idiv dword ptr[esi]		
被除数:eax  商:eax  除数:edx
因为除法结果除了商还有余数,执行前需要将被除数放入eax计算器中,然后在指令中提供除数,除法运算的商会保留在eax计算器中,余数保存在edx计算器中


逻辑运算

与:and 或:or 非: not 异或: xor

and eax, 1

eax = eax & 1;
运算结果保存在目标操作数中,将eax寄存器的值与1进行与运算,并将结果保存在eax寄存器中
or eax, ebx	

eax = eax | ebx;
将eax寄存器的值与ebx进行或运算,并将结果保存在eax寄存器中
not eax	

eax =!eax;
将对eax寄存器的每一位进行取反,并将结果保存在eax寄存器中
xor eax, ecx

eax = eax ^ ecx;

比较

比较大小:cmp 测试:test

cmp eax, 1 
用于比较两个操作数,实际上用的是减法指令,用第一个数减去第二个操作数,不保存运算结果只设置标志寄存器,以用来反映比较结果
test eax, 1
用于比较和测试的指令,主要用于执行两个操作数之间按位逻辑与操作,并根据结果设置标志寄存器eflags的状态标志,同样不保存实际的运算结果

函数调用

调用: call 返回:ret 系统调用: sysenter/ syscall (32位) 系统调用返回:sysexit/ sysret (64位) 中断返回:iret

函数的调用在汇编上就是由两条基本的指令来实现的,call、ret指令 call负责调用,ret指令负责返回原来调用的位置继续执行 一个程序的执行本质就是一层一层的函数调用,所以要存储很多返回地址,而且要一层一层对应存储。X86下选择把这些地址存放在堆栈里面,因为堆栈遵循先进后出、后进先出访问规则,随着函数调用一层层的堆叠,堆栈存储的返回值也对应着一层层堆叠

call xxxx
首先将EIP也就是call指令后面那条指令的地址存入堆栈,这一步目的是在保存返回地址,用于return指令知道能够返回哪里,第二步跳转到后面地址
ret 
从堆栈顶部弹出4个字节,装载到EIP寄存器中,然后跳转到EIP指向的地方执行

堆栈操作

压栈:push 出栈:pop 寄存器批量入栈:pushad 寄存器批量出栈:popad eflags寄存器入栈:pushfd eflags寄存器出栈:popfd

堆一般是负责动态分配内存的地方。栈是进程内存空间里的一片区域,栈的数据结构中栈遵循先进后出、后进先出访问规则。堆栈的增长方向是高地址向低地址方向进行的,栈的顶部是低地址、栈的底部是高地址,其中ESP寄存器始终指向栈顶的位置 堆栈的重要的两个指令: 入栈/压栈(push)就是向堆栈里面放入一个数据,随着数据被push入堆栈,栈顶寄存器ESP的值会自动变化 出栈/弹栈(pop)就是向堆栈里面取出一个数据,随着数据被取出,栈顶寄存器ESP的值会自动变化 也可以通过加减指令修改栈顶的位置

跳转

条件跳转:je/jz/jne/jnz/jb/jnb/jg/jng 无条件跳转:jmp

jmp xxxx
jmp dword ptr[ebx]
无条件跳转,相当与goto指令,跳转到某个地方开始执行,jmp指令后面是要跳转的地方,可以是一个相对地址实际是一个偏移加上eip的值,也可以是一个绝对地址指定跳转到某一地址
JE/JNE:如果等于/不等于(零标志置位/未置位),则跳转
JZ/JNZ:如果等于/不等于(零标志置位/未置位),则跳转
JB/JNB:如果小于/不小于(进位标志置位/未置位),则跳转
JL/JNL:如果小于/不小于(符号标志与溢出标志不一致/一致),则跳转。	
JGE/JNGE:如果大于等于/不大于等于(符号标志与溢出标志一致/不一致),则跳转
JLE/JNLE:如果小于等于/不小于等于(零标志置位或符号标志与溢出标志不一致),则跳转。
JO/JNO:如果溢出/未溢出,则跳转。
JP/JNP:如果奇偶标志置位/未置位,则跳转
N: not,取反
E:equal,相等
B:below,在...以下
L:less,小于
G: greater,大于
O: overflow,溢出
P: parity,奇偶性

这些条判断指令是如何判断条件的呢?与标置寄存器有紧密关系,eflags寄存器中留了一些标志位用来记录CPU执行指令过程中的标记和状态,在一些计算指令和比较指令执行时会同步影响这些标记位 ZF:零标志位 OF:溢出标志位 CF:进出标志位 PF:奇偶标志位 SF:符号标志位

赋值

普通:mov 单字节:movsb 字:movsw 双字:movsd 四字:movsq 取地址:lea

mov eax, 8		

eax = 8;
把8这个立即数赋值给eax寄存器
mov eax, dword ptr[ebx]		

eax = *ebx;
将EBX寄存器的值作为一个地址,将这个地址内的数据赋值给EAX寄存器

movsb、movsw、movsd、movsq 字符串赋值 默认以esi寄存器为源指针,edi寄存器作为目的指针,来进行内存间的数据复制

尝试通过汇编工具分析一下吧!!!

#include <stdio.h>

void if_test(int a) {
	if (a == 1) {
		printf("success");
	}
	else {
		printf("failed");
	}
}

char* switch_case_test(int status) {
	char* mag = NULL;
	switch (status){
	case 200:
		mag = "ok";
		break;
	case 301:
		mag = "redirect";
		break;
	case 404:
		mag = "not found";
		break;
	case 502:
		mag = "server internal error";
		break;
	}

	return mag;
}

void while_test() {
	int n = 100;
	while (n > 0) {
		printf("n=%d\n", n--);
	}
}

void do_while_test() {
	int sum = 0;
	int n = 1;
	do
	{
		sum += n;
		n++;
	} while (n <= 100);
	printf("Sum from 1 to 100 is: %d\n", sum);
}

void for_test() {
	int sum = 0;
	for (int i = 0; i <= 100; i++)
	{
		sum += i;
	}
	printf("Sum from 0 to 100 is: %d\n", sum);
}

int main() {
	// 可以调用函数来测试 
	if_test(1);
	printf("%s\n", switch_case_test(;
	while_test();
	do_while_test();
	for_test();
	return 0;
}

函数调用过程的汇编分析

参数如何传递?返回值如何传递?即函数调用约定

1、__cdecl

使用栈空间传递参数 函数参数按从右往左的方向传递 调用者负责释放参数空间 返回值在寄存器中

2、__stdcall

使用栈空间传递参数 函数参数按从右往左的方向传递 被调用函数负责释放参数空间 返回值在寄存器中

3、__fastcall

两个参数使用寄存器传递 其余参数使用栈从右往左的方向传递 被调用函数负责释放参数空间 返回值在寄存器中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值