2015-04-03 41 views
-2

这组指令有什么作用?这组指令有什么作用?

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

我不明白这些说明会做什么,有人可以解释吗?

+0

我认为“不做任何事”意味着不跳跃?它仍然有东西 – Shade 2015-04-03 20:02:23

+0

@PaulGriffiths听起来像一个答案。 – Shade 2015-04-03 22:01:02

+0

@Shade:同意,评论删除。 – 2015-04-03 22:21:15

回答

1

往前一步来......

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

此:

  1. 发生在rip地址,并增加了0x33b780它。此时,rip包含下一条指令的地址,即0x7ffff7a97760。添加0x33b780即可得到0x7ffff7dd2ee0,这是注释中的地址。

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

我们同意把这个8字节的值叫做“指针”。根据地址的值,0x7ffff7dd2ee0几乎肯定是堆栈中的一个位置。

7ffff7a97760 mov (%rax),%rax 

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

7ffff7a97763 test %rax,%rax 

这会执行一个按位与rax本身,放弃结果,但修改标志。

7ffff7a97766 jne 0x7ffff7a9787a 

这跳转到位置0x7ffff7a9787a如果按位的结果,是不为零,换句话说,如果存储在所述rax值不为零。因此总之,这意味着“找到存储在由rip指示的指针中包含的地址处的8字节值加0x33b780,并且如果该值不为零,则跳转到位置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 

与输出:

[email protected]:~/src/asm$ as -o tso.o tso.s; ld -o tso tso.o 
[email protected]:~/src/asm$ ./tso 
Value of a is zero 
[email protected]:~/src/asm$ 

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

+0

一个简单的问题:为什么他们通过偏移指令指针来访问数据元素?这是常见的吗?自从我用386/486等编写asm代码之后,情况发生了很大变化。我感觉很老!感谢非常好的解释。 – 2015-04-04 00:57:04

+1

@BingBang:这是为了提高位置无关代码的效率,这是共享库所必需的。硬编码内存地址和共享库混合不太好,但如果您知道代码和数据总是至少相距相同的距离,那么通过指令指针引用代码和数据将为您提供一种生成可重定位代码的简单方法。我相信这个能力是在x86_64中引入的。没有这种能力,通常需要有一个间接层,因为相对地址的范围是有限的。 – 2015-04-04 01:06:47

相关问题