这套说明有什么作用?

时间:2015-04-03 16:33:53

标签: assembly x86-64 instructions

这套说明是做什么的?

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

我无法弄清楚这些说明会做什么,有人可以解释一下吗?

1 个答案:

答案 0 :(得分:1)

一步一步......

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

此:

  1. rip中的地址,并为其添加0x33b780。此时,rip包含下一条指令的地址,即0x7ffff7a97760。添加0x33b780会为您提供0x7ffff7dd2ee0,这是评论中的地址。

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

  3. 让我们同意将这个8字节值称为“指针”。根据地址的值,0x7ffff7dd2ee0几乎肯定是堆栈中的一个位置。

    7ffff7a97760    mov    (%rax),%rax
    

    将存储在指针地址中的8字节值复制到rax

    7ffff7a97763    test   %rax,%rax
    

    这会自动执行rax的按位AND,丢弃结果,但会修改标记。

    7ffff7a97766    jne    0x7ffff7a9787a
    

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

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

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

    0

    这是一个完整的程序,显示了这个构造的使用,唯一的区别是我们发现我们的指针引用了帧指针,而不是指针指针:

    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
    

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