0x0000000000400553 <main+59>:   mov    -0x4(%rbp),%eax
0x0000000000400556 <main+62>:   cltq
0x0000000000400558 <main+64>:   shl    $0x3,%rax
0x000000000040055c <main+68>:   mov    %rax,%rdx
实际上我的程序很简单:
5   int main(int argc, char *argv[]) {
6     int i = 0;
7     while(environ[i]) {
8       printf("%s\n", environ[i++]);
9     }
10    return 0;
但是程序集的输出相当长:
Dump of assembler code for function main:
0x0000000000400518 <main+0>:    push   %rbp
0x0000000000400519 <main+1>:    mov    %rsp,%rbp
0x000000000040051c <main+4>:    sub    $0x20,%rsp
0x0000000000400520 <main+8>:    mov    %edi,-0x14(%rbp)
0x0000000000400523 <main+11>:   mov    %rsi,-0x20(%rbp)
0x0000000000400527 <main+15>:   movl   $0x0,-0x4(%rbp)
0x000000000040052e <main+22>:   jmp    0x400553 <main+59>
0x0000000000400530 <main+24>:   mov    -0x4(%rbp),%eax
0x0000000000400533 <main+27>:   cltq
0x0000000000400535 <main+29>:   shl    $0x3,%rax
0x0000000000400539 <main+33>:   mov    %rax,%rdx
0x000000000040053c <main+36>:   mov    0x2003e5(%rip),%rax        # 0x600928 <environ@@GLIBC_2.2.5>
0x0000000000400543 <main+43>:   lea    (%rdx,%rax,1),%rax
0x0000000000400547 <main+47>:   mov    (%rax),%rdi
0x000000000040054a <main+50>:   addl   $0x1,-0x4(%rbp)
0x000000000040054e <main+54>:   callq  0x400418 <puts@plt>
0x0000000000400553 <main+59>:   mov    -0x4(%rbp),%eax
0x0000000000400556 <main+62>:   cltq
0x0000000000400558 <main+64>:   shl    $0x3,%rax
0x000000000040055c <main+68>:   mov    %rax,%rdx
0x000000000040055f <main+71>:   mov    0x2003c2(%rip),%rax        # 0x600928 <environ@@GLIBC_2.2.5>
0x0000000000400566 <main+78>:   lea    (%rdx,%rax,1),%rax
0x000000000040056a <main+82>:   mov    (%rax),%rax
0x000000000040056d <main+85>:   test   %rax,%rax
0x0000000000400570 <main+88>:   jne    0x400530 <main+24>
0x0000000000400572 <main+90>:   mov    $0x0,%eax
0x0000000000400577 <main+95>:   leaveq
0x0000000000400578 <main+96>:   retq
End of assembler dump.
我不明白的是这个块:
0x000000000040052e <main+22>:   jmp    0x400553 <main+59>
0x0000000000400530 <main+24>:   mov    -0x4(%rbp),%eax
0x0000000000400533 <main+27>:   cltq
0x0000000000400535 <main+29>:   shl    $0x3,%rax
0x0000000000400539 <main+33>:   mov    %rax,%rdx
0x000000000040053c <main+36>:   mov    0x2003e5(%rip),%rax        # 0x600928 <environ@@GLIBC_2.2.5>
0x0000000000400543 <main+43>:   lea    (%rdx,%rax,1),%rax
0x0000000000400547 <main+47>:   mov    (%rax),%rdi
0x000000000040054a <main+50>:   addl   $0x1,-0x4(%rbp)
0x000000000040054e <main+54>:   callq  0x400418 <puts@plt>
0x0000000000400553 <main+59>:   mov    -0x4(%rbp),%eax
0x0000000000400556 <main+62>:   cltq
0x0000000000400558 <main+64>:   shl    $0x3,%rax
0x000000000040055c <main+68>:   mov    %rax,%rdx
0x000000000040055f <main+71>:   mov    0x2003c2(%rip),%rax        # 0x600928 <environ@@GLIBC_2.2.5>
0x0000000000400566 <main+78>:   lea    (%rdx,%rax,1),%rax
0x000000000040056a <main+82>:   mov    (%rax),%rax
0x000000000040056d <main+85>:   test   %rax,%rax
0x0000000000400570 <main+88>:   jne    0x400530 <main+24>

最佳答案

助记符
cltq是Intel的gascdqe助记符,如以下文档所述:

助记符是:

  • 将Long转换为Quad(cltq):AT&T风格
  • 将Double转换为Quad扩展https://sourceware.org/binutils/docs/as/i386_002dMnemonics.html

  • 术语:
  • quad(aka四字)== 8字节
  • long(AT&T)==双字(Intel)== 4字节

  • 这是GAS名称与Intel版本非常不同的少数指令之一。 cdqe接受助记符,但是像NASM这样的Intel语法汇编程序只能接受Intel名称。

    效果

    它的符号将4字节扩展为8字节,这在2的补码中表示:
  • 负数,高4个字节的位必须设置为1
  • 正数,必须将其设置为0

  • 在C语言中,通常表示从已签名asint的转换。

    例:
    mov $0123456700000001, %rax  # eax=1, high bytes of rax=garbage
    cltq
    # %rax == $0000 0000 0000 0001
    
    mov $-1, %eax   # %rax = 0000 0000 FFFF FFFF
    cltq
    # %rax == $FFFF FFFF FFFF FFFF == qword $-1
    

    该指令仅适用于64位。

    还请考虑以下说明:
  • long(AT&T CWDE),CWTL(AT&T CBW):CBTW的较小版本,也存在于32位
  • CDQE系列,该符号将CQO扩展为RAX
  • RDX:RAX系列,其符号都可以扩展和移动:( MOVSX ): Intel

  • 带有断言的GitHub上的最小可运行示例:
  • what does movsbl instruction do? CWDE
  • CWTL CDQE

  • C示例

    GCC 4.9.3发出它:
    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char **argv) {
        int i = strtol(argv[1], (char **)NULL, 16);;
        long int l = i;
        printf("%lx\n", l);
    }
    

    编译和反汇编:
    gcc -ggdb3 -std=c99 -O0 a.c
    objdump -S a.out
    

    包含:
        int main(int argc, char **argv) {
      ...
        long int l2 = i;
      400545:       8b 45 fc                mov    -0x4(%rbp),%eax
      400548:       48 98                   cltq
      40054a:       48 89 45 f0             mov    %rax,-0x10(%rbp)
    

    行为是:
    $ ./a.out 0x80000000
    ffffffff80000000
    $ ./a.out 0x40000000
    40000000
    

    07-24 09:44
    查看更多