Assembly 这套指令的作用是什么?

Assembly 这套指令的作用是什么?,assembly,x86-64,instructions,Assembly,X86 64,Instructions,这套指令的作用是什么 7ffff7a97759 mov 0x33b780(%rip),%rax # 0x7ffff7dd2ee0 7ffff7a97760 mov (%rax),%rax 7ffff7a97763 test %rax,%rax 7ffff7a97766 jne 0x7ffff7a9787a 我想不出这些说明会起什么作用,有人能解释一下吗?一步一个脚印 7ffff7a97759 mov

这套指令的作用是什么

   7ffff7a97759    mov    0x33b780(%rip),%rax        # 0x7ffff7dd2ee0
   7ffff7a97760    mov    (%rax),%rax
   7ffff7a97763    test   %rax,%rax
   7ffff7a97766    jne    0x7ffff7a9787a

我想不出这些说明会起什么作用,有人能解释一下吗?

一步一个脚印

7ffff7a97759    mov    0x33b780(%rip),%rax        # 0x7ffff7dd2ee0
这:

  • 获取
    rip
    中的地址,并向其添加
    0x33b780
    。此时,
    rip
    包含下一条指令的地址,即
    0x7ffff7a97760
    。将
    0x33b780
    添加到该注释中,将得到
    0x7ffff7dd2ee0
    ,这是注释中的地址

  • 它将存储在该地址的8字节值复制到
    rax

  • 7ffff7a97763    test   %rax,%rax
    
    让我们同意将这个8字节的值称为“指针”。根据地址的值,
    0x7ffff7dd2ee0
    几乎肯定是堆栈上的一个位置

    7ffff7a97760    mov    (%rax),%rax
    
    这会将存储在指针地址的8字节值复制到
    rax

    7ffff7a97763    test   %rax,%rax
    
    这将对自身执行按位AND of
    rax
    ,丢弃结果,但修改标志

    7ffff7a97766    jne    0x7ffff7a9787a
    
    如果按位AND的结果不为零,换句话说,如果存储在rax中的值不为零,则跳到位置
    0x7ffff7a9787a

    总之,这意味着“找到存储在由
    rip
    0x33b780
    指示的指针中包含的地址处的8字节值,如果该值不为零,则跳转到位置
    0x7fff7a9787a
    ”。例如,在C语言中,存储在
    0x7ffff7dd2ee0
    的指针可能是
    long*
    ,此代码检查它指向的
    long
    是否包含
    0

    它在C中的等价物可能类似于:

    long l = 0;
    long * p = &l;   /*  Assume address of p is 0x7ffff7dd2ee0  */
    
    
    /*  Assembly instructions in your question start here  */
    
    if ( *p == 0 ) {
        /*  This would be the instruction after the jne  */
        /*  Do stuff  */
    }
    
    /*  Location 0x7ffff7a9787a would be here, after the if block  */
    /*  Do other stuff  */
    
    这是一个完整的程序,展示了这种结构的使用,唯一的区别是我们找到的指针是指向帧指针,而不是指向指令指针:

    .global _start
    
            .section .rodata
    
    iszerostr:      .ascii  "Value of a is zero\n"
    isntzerostr:    .ascii  "Value of a is not zero\n"
    
            .section .data
    
    a:      .quad   0x00                    #  We'll be testing this for zero...
    
            .section .text
    
    _start:
            mov     %rsp, %rbp              #  Initialize rbp
            sub     $16, %rsp               #  Allocate stack space
            lea     (a), %rax               #  Store pointer to a in rax...
            mov     %rax, -16(%rbp)         #  ...and then store it on stack
    
            #  Start of the equivalent of your code
    
            mov     -16(%rbp), %rax         #  Load pointer to a into rax
            mov     (%rax), %rax            #  Dereference pointer and get value
            test    %rax, %rax              #  Compare pointed-to value to zero
            jne     .notzero                #  Branch if not zero
    
            #  End of the equivalent of your code
    
    .zero:
            lea     (iszerostr), %rsi       #  Address of string
            mov     $19, %rdx               #  Length of string
            jmp     .end
    
    .notzero:
            lea     (isntzerostr), %rsi     #  Address of string
            mov     $24, %rdx               #  Length of string
    
    .end:
            mov     $1, %rax                #  write() system call number
            mov     $1, %rdi                #  Standard output
            syscall                         #  Make system call
    
            mov     $60, %rax               #  exit() system call number
            mov     $0, %rdi                #  zero exit status
            syscall                         #  Make system call
    
    输出:

    paul@thoth:~/src/asm$ as -o tso.o tso.s; ld -o tso tso.o
    paul@thoth:~/src/asm$ ./tso
    Value of a is zero
    paul@thoth:~/src/asm$ 
    

    顺便提一下,基于指令指针计算偏移量的原因是为了提高位置无关代码的效率,这对于共享库是必要的。硬编码内存地址和共享库不能很好地混合,但是如果您知道代码和数据之间的距离至少是相同的,那么通过指令指针引用代码和数据就可以很容易地生成可重定位代码。如果没有这种能力,通常就需要有一个间接层,因为相对分支的范围通常是有限的。

    我认为“什么都不做”意味着不跳?现在仍然如此stuff@PaulGriffiths这听起来像是一个答案。@Shade:同意,注释已删除。一个简单的问题:他们为什么要通过偏移指令指针来访问数据元素?这是常见的吗?自从我以前在386/486上编写asm代码以来,情况发生了很大变化。。我觉得自己老了!谢谢你的精彩解释。@BingBang:这是为了提高位置无关代码的效率,这是共享库所必需的。硬编码内存地址和共享库不能很好地混合,但是如果您知道代码和数据之间的距离至少是相同的,那么通过指令指针引用代码和数据就可以很容易地生成可重定位代码。我相信这项功能是在x86_64中引入的。如果没有这种能力,通常需要一层间接寻址,因为相对地址的范围是有限的。