zoukankan      html  css  js  c++  java
  • 常用寄存器说明、汇编代码详解

    常用寄存器说明、汇编代码详解

    0. 什么是寄存器
    0.1 概念
    1. 什么是寄存器:
    2. 寄存器作用:
    0.2 通俗易懂理解寄存器
    1. 数据寄存器
    1.1 ax/eax/rax 累加(Accumulator)寄存器
    1.2 bx/ebx/rbx 基址(Base)寄存器
    1.3 cx/ecx/rcx 计数器(Counter)寄存器
    1.4 dx/edx/rdx 数据(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. 标志寄存器
    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. 函数帧:
    10.1 函数帧概念:
    10.2 gdb 调试:
    1. frame num
    11. 代码例子4:
    11.1 huibian2.c
    11.2 汇编代码及解释(注意x86 和 mips 汇编返过来操作的)
    参考
    0. 什么是寄存器

    0.1 概念

    1. 什么是寄存器:

    CPU 本身只负责运算,不负责储存数据。数据一般都储存在内存之中,CPU 要用的时候就去内存读写数据。但是,CPU 的运算速度远高于内存的读写速度,为了避免被拖慢,CPU 都自带一级缓存和二级缓存。基本上,CPU 缓存可以看作是读写速度较快的内存。

    但是,CPU 缓存还是不够快,另外数据在缓存里面的地址是不固定的,CPU 每次读写都要寻址也会拖慢速度。因此,除了缓存之外,CPU 还自带了寄存器(register),用来储存最常用的数据。也就是说,那些最频繁读写的数据(比如循环变量),都会放在寄存器里面,CPU 优先读写寄存器,再由寄存器跟内存交换数据。

    2. 寄存器作用:

    寄存器是CPU的组成部部分,用来暂存指令、数据和地址
    是有限存储容量的高速存储部件,其读写速度是最快的,不需要IO传输
    寄存器的作用主要是:
    可将寄存器内的数据执行算术及逻辑运算;
    存于寄存器内的地址可用来指向内存的某个位置,即寻址;
    可以用来读写数据到电脑的周边设备。
    0.2 通俗易懂理解寄存器

    寄存器就是你的口袋。身上只有那么几个,只装最常用或者马上要用的东西。
    内存就是你的背包。有时候拿点什么放到口袋里,有时候从口袋里拿出点东西放在背包里。
    辅存就是你家里的抽屉。可以放很多东西,但存取不方便。

    常用寄存器
    16/32/64位

    1. 数据寄存器

    1.1 ax/eax/rax 累加(Accumulator)寄存器

    常用于乘、除法和函数返回值

    1.2 bx/ebx/rbx 基址(Base)寄存器

    被调用者保存/常做内存数据的指针, 或者说常以它为基址来访问内存.

    1.3 cx/ecx/rcx 计数器(Counter)寄存器

    常做字符串和循环操作中的计数器

    1.4 dx/edx/rdx 数据(Data)寄存器

    常用于乘、除法和 I/O 指针

    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. 段寄存器

    CS——代码段寄存器(CodeSegmentRegister),其值为代码段的段值;
    DS——数据段寄存器(DataSegmentRegister),其值为数据段的段值;
    SS——堆栈段寄存器(StackSegmentRegister),其值为堆栈段的段值;
    ES——附加段寄存器(ExtraSegmentRegister),其值为附加数据段的段值;
    FS——附加段寄存器(ExtraSegmentRegister),其值为附加数据段的段值(32位CPU新增);
    GS——附加段寄存器(ExtraSegmentRegister),其值为附加数据段的段值(32位CPU新增)。

    5. 标志寄存器

    进位标志CF(CarryFlag)
    奇偶标志PF(ParityFlag)
    辅助进位标志AF(AuxiliaryCarryFlag)
    零标志ZF(ZeroFlag)
    符号标志SF(SignFlag)
    溢出标志OF(OverflowFlag)

    6. 其他寄存器:EIP寄存器

    EIP寄存器
    用来存储CPU要读取指令的地址,CPU通过EIP寄存器读取即将要执行的指令。每次CPU执行完相应的汇编指令之后,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. 函数帧:

    10.1 函数帧概念:

    函数调用栈由连续的栈帧组成。每个栈帧记录一个函数调用的信息,这些信息包括函数参数,函数变量,函数运行地址。

    当程序启动后,栈中只有一个帧,这个帧就是main函数的帧。我们把这个帧叫做初始化帧或者叫做最外层帧。
    每当一个函数被调用,一个新帧将被建立,每当一个函数返回时,函数帧将被剔除。
    如果函数是个递归函数,栈中将有很多帧是
    记录同一个函数的。但前执行的函数的帧被称作最深帧,这个帧是现存栈中最近被创建的帧。

    10.2 gdb 调试:

    gdb 为所有存活的栈帧分配一个数字编号,最深帧的编号是0,被它调用的内个帧的编号就是1。
    这些编号子程序中是不存在的,只不过时调试的时候被gdb用的。

    关于函数帧的两个指令:

    1. frame num

    移动到 num 指定的栈帧中去,并打印选中的栈的信息。如: frame 3
    num 可以时帧编号或者时帧的地址。如果没有args,则打印当前帧的信息。

    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 字节处
    7: 48 89 75 e0 mov %rsi,-0x20(%rbp) //rsi 寄存器中的值 20 放到 rbp 寄存器向下移动 32 字节处
    b: 8b 45 ec mov -0x14(%rbp),%eax //bp 寄存器向下移动20字节 就是 10 放到 eax 寄存器中
    e: 89 45 fc mov %eax,-0x4(%rbp) //eax中的值 就是10 放到 bp 向下4字节出 也就是变量c中
    11: 48 8b 45 e0 mov -0x20(%rbp),%rax // bp 向下32字节 也就是 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> //调用 callee 函数
    30: R_X86_64_PC32 callee-0x4
    34: 89 45 fc mov %eax,-0x4(%rbp) // 将上面 callee 返回值 30 存到 bp -4字节处 也就是 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> // 调用 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
    ————————————————
    版权声明:本文为CSDN博主「Hani_97」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/lqy971966/article/details/106780755

  • 相关阅读:
    js 注意
    JS学习大作业-Excel
    js继承
    转载:margin外边距合并问题以及解决方式
    CSS属性选择器和部分伪类
    HTML使用CSS样式的方法
    link元素 rel src href属性
    【2020.01.06】SDN大作业
    【2019.12.11】SDN上机第7次作业
    【2019.12.04】SDN上机第6次作业
  • 原文地址:https://www.cnblogs.com/Alex80/p/14851679.html
Copyright © 2011-2022 走看看