控制寄存器控制运行模式
rax 64位 8B 只有64位CPU才有
eax 32位 4B 32位,64位CPU都有
ax 16位 2B 16位,32位,64位CPU都有
al 8位 1B 8位,16位,32位,64位CPU都有
ah 8位 1B 8位,16位,32位,64位CPU都有
注意:只有rax,rbx,rcx,rdx有ah/bh/ch/dh高八位寄存器
特殊用途:
1.rax:用于函数返回值的接收
2.rcx:循环次数,this指针(C++)
3.rsi:source 源数据
4.rdi:destination 目的数据
5.rbp,rsp:栈寄存器
6.esp:栈顶
7.ebp:栈底
使用汇编写出以下代码:
int a=10;
a +=1;
1.用多个寄存器实现
xor eax,eax
mov eax,0x0A
add eax,1
mov [ebp-8],eax
2.只用一个寄存器实现
xor eax,eax
xor ebx,ebx
mov eax,0x0A
mov ebx,0x01
add eax,ebx
mov [ebp-8],eax
跳转指令:
短跳转:call,jmp,jcc
长跳转:中断,跨段
函数调用前后栈是不变的
int main()
{
00831750 push ebp
00831751 mov ebp,esp
00831753 sub esp,0CCh
------------------------------------------开辟栈栈帧
00831759 push ebx
0083175A push esi
0083175B push edi
-----------------------------------------保存现场
0083175C lea edi,[ebp-0Ch]
0083175F mov ecx,3
00831764 mov eax,0CCCCCCCCh
00831769 rep stos dword ptr es:[edi]
0083176B mov ecx,offset _FEA7E5C2_main@c (083C008h)
00831770 call @__CheckForDebuggerJustMyCode@4 (0831307h)
-----------------------------------------初始化开辟的栈空间
int a = 0;
00831775 mov dword ptr [a],0
return 0;
0083177C xor eax,eax
}
0083177E pop edi
0083177F pop esi
00831780 pop ebx
-----------------------------------------恢复现场
00831781 add esp,0CCh
00831787 cmp ebp,esp
00831789 call __RTC_CheckEsp (0831230h)
0083178E mov esp,ebp
00831790 pop ebp
-----------------------------------------恢复栈帧
00831791 ret ;和call对应,拿到返回地址
-----------------------------------------返回
esp:栈顶
ebp:栈底
mov esp,ebp
pop ebp
leave可以代替这两条,命令(复杂指令集)
运行模式:
实模式 16 2B
保护模式 32 4B
长模式 64 8B
1.push:把数据压入栈,栈后移(减小)
栈顶指针先移动,然后赋值
sub esp,4
mov dword ptr[esp],10
2.pop:取出数据,栈前移(增大)
先取值,栈顶指针在移动
mov eax,[esp]
add esp,4
3.jmp:无条件跳转
jmp 地KERNEL_ARRD 段内跳 短跳
jmp CODE_SELECTOR:KERNEL_ARRD 跨段跳 长跳
4.call
1.会把call指令的下一条指令地址压入栈
2.跳转到函数里面
5.ret
1.取到栈顶的地址,且栈前移(增大)
2.回到地址的位置
给出一下C语言,转化成汇编语言
void text() {
int a = 9;
if (10 == a)
{
a = 100;
}
else
{
a = 1000;
}
}
int main(int argc,char* argv[])
{
text();
return 0;
}
汇编:
global text
text:
push ebp ;保存main的栈底
mov ebp,esp ;将main栈顶赋值给text栈底
mov [esp-8],0x0A
mov eax,[esp-8]
cmp eax,0X0A
jne .s
mov [esp-8],OX64
jmp .r
.s
mov [esp-8],0X3E8
.r
mov eax,[esp-8] ;保存返回值到eax寄存器中
leave ;mov esp,ebp;popebp
ret ;返回
main:
call text ;将下一条指令的地址压入栈中,跳转到text函数
ret
堆栈平衡(平栈):
(1)调用者平栈:外平栈 add esp,4
(2)被调用者平栈:内平栈 ret 8
调用约定:
研究调用约定主要研究,传参方式(栈传参,寄存器,栈+寄存器)和传参顺序,平栈方式
32Bit:
1.__cdecl:(X86)默认约定
text(0x11,0x22,0x33);
002D1DE1 push 33h
002D1DE3 push 22h
002D1DE5 push 11h
002D1DE7 call _text (02D13BBh)
002D1DEC add esp,0Ch ;一个参数4字节一共12字节
栈传参,从右到左,外平栈
2.__stdcall:windows动态链接库
00BF1DE1 push 33h
00BF1DE3 push 22h
00BF1DE5 push 11h
00BF1DE7 call _text@12 (0BF13C0h)
栈传参,从右到左,内平栈
3.__fastcall
00AC3E71 push 33h
00AC3E73 mov edx,22h
00AC3E78 mov ecx,11h
00AC3E7D call @text@12 (0AC13C5h)
前两个寄存器,其余的栈传参,从右到左,内平栈
64Bit:
Windows:__fastcall
text(0x11,0x22,0x33,0x44,0x55,0x66,0x77);
00007FF7142E1B83 mov dword ptr [rsp+30h],77h
00007FF7142E1B8B mov dword ptr [rsp+28h],66h
00007FF7142E1B93 mov dword ptr [rsp+20h],55h
00007FF7142E1B9B mov r9d,44h
00007FF7142E1BA1 mov r8d,33h
00007FF7142E1BA7 mov edx,22h
00007FF7142E1BAC mov ecx,11h
00007FF7142E1BB1 call text (07FF7142E13A2h)
前六个寄存器,其余的栈传参,从左到右,内平栈
Linux: AMD64 ABI
使用场景:
1.直接访问底层硬件
2.使用特定的处理器指令
3.性能优化
4.实现特殊的程序逻辑
Linux内联语法:
在 Linux 中,内联汇编语法通常使用 asm
关键字来嵌入汇编代码到 C/C++ 程序中。内联汇编语法的基本格式如下:
asm("assembly code" : output : input : clobbered);
其中,assembly code
是要嵌入的汇编代码,output
是输出操作数,input
是输入操作数,clobbered
是会被修改的寄存器。
assembly code
:这里放置你的汇编代码。output
:声明输出变量,可以是寄存器或内存地址。input
:声明输入变量,可以是寄存器或内存地址。clobbered
:声明可能被修改的寄存器。示例1:
int myFunction(int arg1, int arg2);
int main() {
int arg1 = 1;
int arg2 = 4;
int add = 0;
asm volatile (
"push $100\n" // 将 arg2 压入栈
"push $200\n" // 将 arg1 压入栈
"call myFunction\n" // 调用 myFunction函数
"add $8, %%esp\n" // 平栈
:"=eax"(add) //接收返回值
:
:
);
printf("%d\n",add);
return 0;
}
int myFunction(int arg1, int arg2) {
return arg1-arg2;
}
示例2
int myFunction(int arg1, int arg2);
int main() {
int arg1 = 1;
int arg2 = 4;
int add = 0;
asm volatile (
"push %[arg2]\n" // 将 arg2 压入栈
"push %[arg1]\n" // 将 arg1 压入栈
"call myFunction\n" // 调用 myFunction
"add $8, %%esp\n" // 平栈
:"=eax"(add) //接受返回值
: [arg2] "r" (arg2),[arg1] "r" (arg1) //传入值重名[],随机寄存器
:
);
printf("%d\n",add);
return 0;
}
int myFunction(int arg1, int arg2) {
return arg1-arg2;
}