常用寄存器说明、汇编代码详解
常用寄存器說明、匯編代碼詳解
0. 什么是寄存器
0.1 概念
1. 什么是寄存器:
2. 寄存器作用:
0.2 通俗易懂理解寄存器
1. 數(shù)據(jù)寄存器
1.1 ax/eax/rax 累加(Accumulator)寄存器
1.2 bx/ebx/rbx 基址(Base)寄存器
1.3 cx/ecx/rcx 計數(shù)器(Counter)寄存器
1.4 dx/edx/rdx 數(shù)據(jù)(Data)寄存器
2. 變址寄存器
2.1 si/esi/rsi 來源索引(Source Index)寄存器
2.2 di/edi/rdi 目的索引(Destination Index)
3. 指針寄存器
3.1 bp/ebp/rbp 基址指針(Base Point)寄存器
3.2 sp/esp/rsp 堆棧指針(Stack Point)寄存器
4. 段寄存器
5. 標(biāo)志寄存器
6. 其他寄存器:EIP寄存器
7. 參考圖
7.1 注意x86 和 mips 匯編返回來的 操作 如 x86中試 mov 左給右賦值,mips反過來的
8. 代碼例子
8.1 register.c
8.2 objdump -x -s -d register.o
9 代碼例子2
9.1 簡單代碼:
9.2 代碼匯編說明:
10. 函數(shù)幀:
10.1 函數(shù)幀概念:
10.2 gdb 調(diào)試:
1. frame num
11. 代碼例子4:
11.1 huibian2.c
11.2 匯編代碼及解釋(注意x86 和 mips 匯編返過來操作的)
參考
0. 什么是寄存器
0.1 概念
1. 什么是寄存器:
CPU 本身只負(fù)責(zé)運(yùn)算,不負(fù)責(zé)儲存數(shù)據(jù)。數(shù)據(jù)一般都儲存在內(nèi)存之中,CPU 要用的時候就去內(nèi)存讀寫數(shù)據(jù)。但是,CPU 的運(yùn)算速度遠(yuǎn)高于內(nèi)存的讀寫速度,為了避免被拖慢,CPU 都自帶一級緩存和二級緩存?;旧?,CPU 緩存可以看作是讀寫速度較快的內(nèi)存。
但是,CPU 緩存還是不夠快,另外數(shù)據(jù)在緩存里面的地址是不固定的,CPU 每次讀寫都要尋址也會拖慢速度。因此,除了緩存之外,CPU 還自帶了寄存器(register),用來儲存最常用的數(shù)據(jù)。也就是說,那些最頻繁讀寫的數(shù)據(jù)(比如循環(huán)變量),都會放在寄存器里面,CPU 優(yōu)先讀寫寄存器,再由寄存器跟內(nèi)存交換數(shù)據(jù)。
2. 寄存器作用:
寄存器是CPU的組成部部分,用來暫存指令、數(shù)據(jù)和地址
是有限存儲容量的高速存儲部件,其讀寫速度是最快的,不需要IO傳輸
寄存器的作用主要是:
可將寄存器內(nèi)的數(shù)據(jù)執(zhí)行算術(shù)及邏輯運(yùn)算;
存于寄存器內(nèi)的地址可用來指向內(nèi)存的某個位置,即尋址;
可以用來讀寫數(shù)據(jù)到電腦的周邊設(shè)備。
0.2 通俗易懂理解寄存器
寄存器就是你的口袋。身上只有那么幾個,只裝最常用或者馬上要用的東西。
內(nèi)存就是你的背包。有時候拿點什么放到口袋里,有時候從口袋里拿出點東西放在背包里。
輔存就是你家里的抽屜??梢苑藕芏鄸|西,但存取不方便。
常用寄存器
16/32/64位
1. 數(shù)據(jù)寄存器
1.1 ax/eax/rax 累加(Accumulator)寄存器
常用于乘、除法和函數(shù)返回值
1.2 bx/ebx/rbx 基址(Base)寄存器
被調(diào)用者保存/常做內(nèi)存數(shù)據(jù)的指針, 或者說常以它為基址來訪問內(nèi)存.
1.3 cx/ecx/rcx 計數(shù)器(Counter)寄存器
常做字符串和循環(huán)操作中的計數(shù)器
1.4 dx/edx/rdx 數(shù)據(jù)(Data)寄存器
常用于乘、除法和 I/O 指針
2. 變址寄存器
2.1 si/esi/rsi 來源索引(Source Index)寄存器
存儲器指針、串指令中的源操作數(shù)指針
2.2 di/edi/rdi 目的索引(Destination Index)
存儲器指針、串指令中的目的操作數(shù)指針
3. 指針寄存器
3.1 bp/ebp/rbp 基址指針(Base Point)寄存器
被調(diào)用者保存/棧基址寄存器-指向棧底
3.2 sp/esp/rsp 堆棧指針(Stack Point)寄存器
棧寄存器-指向棧頂
4. 段寄存器
CS——代碼段寄存器(CodeSegmentRegister),其值為代碼段的段值;
DS——數(shù)據(jù)段寄存器(DataSegmentRegister),其值為數(shù)據(jù)段的段值;
SS——堆棧段寄存器(StackSegmentRegister),其值為堆棧段的段值;
ES——附加段寄存器(ExtraSegmentRegister),其值為附加數(shù)據(jù)段的段值;
FS——附加段寄存器(ExtraSegmentRegister),其值為附加數(shù)據(jù)段的段值(32位CPU新增);
GS——附加段寄存器(ExtraSegmentRegister),其值為附加數(shù)據(jù)段的段值(32位CPU新增)。
5. 標(biāo)志寄存器
進(jìn)位標(biāo)志CF(CarryFlag)
奇偶標(biāo)志PF(ParityFlag)
輔助進(jìn)位標(biāo)志AF(AuxiliaryCarryFlag)
零標(biāo)志ZF(ZeroFlag)
符號標(biāo)志SF(SignFlag)
溢出標(biāo)志OF(OverflowFlag)
6. 其他寄存器:EIP寄存器
EIP寄存器
用來存儲CPU要讀取指令的地址,CPU通過EIP寄存器讀取即將要執(zhí)行的指令。每次CPU執(zhí)行完相應(yīng)的匯編指令之后,EIP寄存器的值就會增加。
7. 參考圖
7.1 注意x86 和 mips 匯編返回來的 操作 如 x86中試 mov 左給右賦值,mips反過來的
8. 代碼例子
8.1 register.c
gcc -c register.c -o register.o
root@ubuntu-admin-a1:/home# cat register.c
#include<stdio.h>
int printf(const char* format,...);
int g_init_var = 2;
int g_uinit_var;
void func1(int i)
{
int res = i*i;
int iLoop = 0;
for(iLoop = 0;iLoop < 3;iLoop++)
{
printf("iLoop = %d
",iLoop);
}
printf("%d
",i);
printf("i*i = %d
",res);
}
int main()
{
static int iStaticVar = 3;
static int iStaticVar2;
int a = 1;
int b;
func1(iStaticVar + iStaticVar2 + a + b);
return 0;
}
root@ubuntu-admin-a1:/home#
8.2 objdump -x -s -d register.o
root@ubuntu-admin-a1:/home# objdump -x -s -d register.o
…………省略
…………省略
0000000000000000 <func1>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 83 ec 20 sub $0x20,%rsp
8: 89 7d ec mov %edi,-0x14(%rbp)
b: 8b 45 ec mov -0x14(%rbp),%eax
e: 0f af 45 ec imul -0x14(%rbp),%eax
12: 89 45 fc mov %eax,-0x4(%rbp)
15: c7 45 f8 00 00 00 00 movl $0x0,-0x8(%rbp)
1c: c7 45 f8 00 00 00 00 movl $0x0,-0x8(%rbp)
23: eb 18 jmp 3d <func1+0x3d>
25: 8b 45 f8 mov -0x8(%rbp),%eax
28: 89 c6 mov %eax,%esi
2a: bf 00 00 00 00 mov $0x0,%edi
2b: R_X86_64_32 .rodata
2f: b8 00 00 00 00 mov $0x0,%eax
34: e8 00 00 00 00 callq 39 <func1+0x39>
35: R_X86_64_PC32 printf-0x4
39: 83 45 f8 01 addl $0x1,-0x8(%rbp)
3d: 83 7d f8 02 cmpl $0x2,-0x8(%rbp)
41: 7e e2 jle 25 <func1+0x25>
43: 8b 45 ec mov -0x14(%rbp),%eax
46: 89 c6 mov %eax,%esi
48: bf 00 00 00 00 mov $0x0,%edi
49: R_X86_64_32 .rodata+0xc
4d: b8 00 00 00 00 mov $0x0,%eax
52: e8 00 00 00 00 callq 57 <func1+0x57>
53: R_X86_64_PC32 printf-0x4
57: 8b 45 fc mov -0x4(%rbp),%eax
5a: 89 c6 mov %eax,%esi
5c: bf 00 00 00 00 mov $0x0,%edi
5d: R_X86_64_32 .rodata+0x10
61: b8 00 00 00 00 mov $0x0,%eax
66: e8 00 00 00 00 callq 6b <func1+0x6b>
67: R_X86_64_PC32 printf-0x4
6b: 90 nop
6c: c9 leaveq
6d: c3 retq
000000000000006e <main>:
6e: 55 push %rbp
6f: 48 89 e5 mov %rsp,%rbp
72: 48 83 ec 10 sub $0x10,%rsp
76: c7 45 f8 01 00 00 00 movl $0x1,-0x8(%rbp)
7d: 8b 15 00 00 00 00 mov 0x0(%rip),%edx # 83 <main+0x15>
7f: R_X86_64_PC32 .data
83: 8b 05 00 00 00 00 mov 0x0(%rip),%eax # 89 <main+0x1b>
85: R_X86_64_PC32 .bss-0x4
89: 01 c2 add %eax,%edx
8b: 8b 45 f8 mov -0x8(%rbp),%eax
8e: 01 c2 add %eax,%edx
90: 8b 45 fc mov -0x4(%rbp),%eax
93: 01 d0 add %edx,%eax
95: 89 c7 mov %eax,%edi
97: e8 00 00 00 00 callq 9c <main+0x2e>
98: R_X86_64_PC32 func1-0x4
9c: b8 00 00 00 00 mov $0x0,%eax
a1: c9 leaveq
a2: c3 retq
root@ubuntu-admin-a1:/home#
參考:
http://www.ruanyifeng.com/blog/2018/01/assembly-language-primer.html
10. 函數(shù)幀:
10.1 函數(shù)幀概念:
函數(shù)調(diào)用棧由連續(xù)的棧幀組成。每個棧幀記錄一個函數(shù)調(diào)用的信息,這些信息包括函數(shù)參數(shù),函數(shù)變量,函數(shù)運(yùn)行地址。
當(dāng)程序啟動后,棧中只有一個幀,這個幀就是main函數(shù)的幀。我們把這個幀叫做初始化幀或者叫做最外層幀。
每當(dāng)一個函數(shù)被調(diào)用,一個新幀將被建立,每當(dāng)一個函數(shù)返回時,函數(shù)幀將被剔除。
如果函數(shù)是個遞歸函數(shù),棧中將有很多幀是
記錄同一個函數(shù)的。但前執(zhí)行的函數(shù)的幀被稱作最深幀,這個幀是現(xiàn)存棧中最近被創(chuàng)建的幀。
10.2 gdb 調(diào)試:
gdb 為所有存活的棧幀分配一個數(shù)字編號,最深幀的編號是0,被它調(diào)用的內(nèi)個幀的編號就是1。
這些編號子程序中是不存在的,只不過時調(diào)試的時候被gdb用的。
關(guān)于函數(shù)幀的兩個指令:
1. frame num
移動到 num 指定的棧幀中去,并打印選中的棧的信息。如: frame 3
num 可以時幀編號或者時幀的地址。如果沒有args,則打印當(dāng)前幀的信息。
11. 代碼例子4:
11.1 huibian2.c
#include <stdio.h>
#include <stdlib.h>
int callee(int a, long b) {
int c = a;
c += (int)b;
return c;
}
void caller() {
int v = callee(10, 20);
printf("v=%d
", v);
}
int main(int argc, char** argv)
{
caller();
return 0;
}
11.2 匯編代碼及解釋(注意x86 和 mips 匯編返過來操作的)
注意x86 和 mips 匯編返回來的 操作 如 x86中試 mov 左給右賦值,mips反過來的
[root@localhost home]# gcc -c huibian2.c -o hui2.o
[root@localhost home]# objdump -x -s -d hui2.o
0000000000000000 <callee>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 89 7d ec mov %edi,-0x14(%rbp) //edi寄存器中的值 10 放到 rbp 寄存器向下移動 20 字節(jié)處
7: 48 89 75 e0 mov %rsi,-0x20(%rbp) //rsi 寄存器中的值 20 放到 rbp 寄存器向下移動 32 字節(jié)處
b: 8b 45 ec mov -0x14(%rbp),%eax //bp 寄存器向下移動20字節(jié) 就是 10 放到 eax 寄存器中
e: 89 45 fc mov %eax,-0x4(%rbp) //eax中的值 就是10 放到 bp 向下4字節(jié)出 也就是變量c中
11: 48 8b 45 e0 mov -0x20(%rbp),%rax // bp 向下32字節(jié) 也就是 20 放到寄存器 rax 中
15: 01 45 fc add %eax,-0x4(%rbp) // rbp = (rbp - 4) + eax 就是 20 + 10
18: 8b 45 fc mov -0x4(%rbp),%eax // 將 30 放到 eax 寄存器中
1b: 5d pop %rbp
1c: c3 retq
000000000000001d <caller>:
1d: 55 push %rbp
1e: 48 89 e5 mov %rsp,%rbp
21: 48 83 ec 10 sub $0x10,%rsp //開棧
25: be 14 00 00 00 mov $0x14,%esi //將 20 賦值給 esi 寄存器
2a: bf 0a 00 00 00 mov $0xa,%edi //將 10 賦值給 edi 寄存器
2f: e8 00 00 00 00 callq 34 <caller+0x17> //調(diào)用 callee 函數(shù)
30: R_X86_64_PC32 callee-0x4
34: 89 45 fc mov %eax,-0x4(%rbp) // 將上面 callee 返回值 30 存到 bp -4字節(jié)處 也就是 v 中
37: 8b 45 fc mov -0x4(%rbp),%eax
3a: 89 c6 mov %eax,%esi
3c: bf 00 00 00 00 mov $0x0,%edi
3d: R_X86_64_32 .rodata
41: b8 00 00 00 00 mov $0x0,%eax
46: e8 00 00 00 00 callq 4b <caller+0x2e> // 調(diào)用 printf 打印
47: R_X86_64_PC32 printf-0x4
4b: c9 leaveq
4c: c3 retq
000000000000004d <main>:
4d: 55 push %rbp
4e: 48 89 e5 mov %rsp,%rbp
51: 48 83 ec 10 sub $0x10,%rsp //開棧
55: 89 7d fc mov %edi,-0x4(%rbp)
58: 48 89 75 f0 mov %rsi,-0x10(%rbp)
5c: b8 00 00 00 00 mov $0x0,%eax
61: e8 00 00 00 00 callq 66 <main+0x19>
62: R_X86_64_PC32 caller-0x4
66: b8 00 00 00 00 mov $0x0,%eax
6b: c9 leaveq
6c: c3 retq
[root@localhost home]#
參考
https://www.cnblogs.com/findumars/p/4121962.html
https://blog.csdn.net/striver1205/article/details/25420891
————————————————
版權(quán)聲明:本文為CSDN博主「Hani_97」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/lqy971966/article/details/106780755
總結(jié)
以上是生活随笔為你收集整理的常用寄存器说明、汇编代码详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 吃货联盟订餐系统(二)
- 下一篇: 使用和学习 ES2015