【问题标题】:Understanding these assembly instructions [closed]了解这些组装说明[关闭]
【发布时间】:2016-01-02 09:46:27
【问题描述】:

我正在通过编写 C 程序和查看汇编输出来学习汇编。我在页面底部包含了 C 程序以使其更容易。我正在努力理解一条装配线:

cdqe

movzx eax, BYTE PTR [rbp-32+rax]

movsx eax, al

所以我认为 cdqe 将 eax 扩展为 rax(64 位)。很明显,我要打印的字符串适合 al 寄存器,但我不明白 rbp-32+rax 深处发生了什么。谁能帮我解释一下?

.file   "string_manip.c"
    .intel_syntax noprefix
    .section    .rodata
.LC0:
    .string "Hello"
    .string ""
    .zero   3
    .text
    .globl  main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    push    rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    mov rbp, rsp
    .cfi_def_cfa_register 6
    sub rsp, 48
    mov rax, QWORD PTR fs:40
    mov QWORD PTR [rbp-8], rax
    xor eax, eax
    mov DWORD PTR [rbp-36], 0
    mov eax, DWORD PTR .LC0[rip]
    mov DWORD PTR [rbp-32], eax
    movzx   eax, WORD PTR .LC0[rip+4]
    mov WORD PTR [rbp-28], ax
    movzx   eax, BYTE PTR .LC0[rip+6]
    mov BYTE PTR [rbp-26], al
    mov WORD PTR [rbp-25], 0
    mov BYTE PTR [rbp-23], 0
    mov DWORD PTR [rbp-36], 0
    jmp .L2
.L3:
    mov eax, DWORD PTR [rbp-36]
    cdqe
    movzx   eax, BYTE PTR [rbp-32+rax] <--- what is this doing?
    movsx   eax, al
    mov edi, eax
    call    putchar
    add DWORD PTR [rbp-36], 1
.L2:
    cmp DWORD PTR [rbp-36], 5
    jle .L3
    mov edi, 10
    call    putchar
    mov eax, 0
    mov rdx, QWORD PTR [rbp-8]
    xor rdx, QWORD PTR fs:40
    je  .L5
    call    __stack_chk_fail
.L5:
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   main, .-main
    .ident  "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4"
    .section    .note.GNU-stack,"",@progbits


#include <string.h>
#include <stdio.h>

int main()
{
    int i = 0;
    char array[10] = "Hello\0";
    for(i=0; i<6; i++)
        printf("%c", array[i]);
    printf("\n");
    return 0;
}

【问题讨论】:

  • 它对rbp-32+rax指向的字节进行零扩展(无符号向上转换)并将其移动到eax;想想uint32_t eax = *(uint8_t *)(rbp - 32 + rax);
  • 您将有更好的时间阅读-Og -fverbose-asm 的编译器输出。 -O0 太吵了(到处都是商店和重新加载)。您必须跟踪所有数据移动,以查看重新加载的变量是相同的变量还是不同的变量。我宁愿看-O3 的输出来“看看编译器做了什么”,但我已经知道 asm,我唯一感兴趣的是看看编译器是否发现了我没有发现的任何聪明的优化。 :P 但说真的,如果你知道编译器通常做什么,你可以遵循优化的代码。 -Og 是目前为止最适合学习的,或者说 O1。

标签: c assembly cpu-registers


【解决方案1】:

它只是计算其中一个字符的地址。

大概您的字符串从rbp-32 开始,然后指令执行与ch = string[rax] 等效的C。

我猜这是未优化的代码,所以编译器做了一些额外的符号扩展和零扩展,这并不是真正需要的。

【讨论】:

  • 是的,字符串确实从 rbp-32 开始,但我想知道为什么它对于 rbp-32+rax 的 +rax 部分是必要的。如果字符串从 rbp-32 开始,我们可以不使用它吗?感谢“计算字符地址”,总结的很好
  • .L2 似乎有一个循环,它增加了一些东西并返回到.L3。此外,由于这看起来像未优化的 C,因此汇编代码做了很多优化器会减少的事情。就像使用指向字符串的单个指针一样,并增加指针而不是增加索引。并且也许将所有内容都保存在循环中的寄存器中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多