程序集中的内存分配和寻址

时间:2019-01-17 05:01:40

标签: c assembly x86-64

我正在尝试学习汇编,那里有一些我不完全理解其目的的说明。

C代码

#include <stdio.h>

int main(int argc, char* argv[])
{
    printf("Argument One - %s\n", argv[1]);
    return 0;
}

组装

    .section    __TEXT,__text,regular,pure_instructions
    .build_version macos, 10, 14
    .intel_syntax noprefix
    .globl  _main                   ## -- Begin function main
    .p2align    4, 0x90
_main:                                  ## @main
## %bb.0:
    push    rbp
    mov rbp, rsp
    sub rsp, 32
    lea rax, [rip + L_.str]
    mov dword ptr [rbp - 4], 0
    mov dword ptr [rbp - 8], edi
    mov qword ptr [rbp - 16], rsi
    mov rsi, qword ptr [rbp - 16]
    mov rsi, qword ptr [rsi + 8]
    mov rdi, rax
    mov al, 0
    call    _printf
    xor ecx, ecx
    mov dword ptr [rbp - 20], eax ## 4-byte Spill
    mov eax, ecx
    add rsp, 32
    pop rbp
    ret
                                        ## -- End function
    .section    __TEXT,__cstring,cstring_literals
L_.str:                                 ## @.str
    .asciz  "Argument One - %s\n"


.subsections_via_symbols

Q1。 sub rsp,32

当没有局部变量时,为什么要为32个字节分配空间?我相信argc和argv分别保存在寄存器edi和rsi中。如果可以将它们移动到堆栈上,那岂不是只需要12个字节?

Q2。 lea rax,[rip + L_.str] mov rdi,rax

我是否正确理解L_.str具有字符串““ Argument One-%s \ n””的地址?从我的理解中,printf可通过寄存器rdi访问此字符串。指令 mov rdi,L_.str 不起作用吗?

Q3。 mov dword ptr [rbp-4],0

为什么零被压入堆栈?

Q4。 mov dword ptr [rbp-8],edi mov qword ptr [rbp-16],rsi

我相信这些指令是将argc和argv放入堆栈。使用edi和rsi是否纯粹是惯例?

Q5。 mov dword ptr [rbp-20],eax

我不知道这是怎么做的。

1 个答案:

答案 0 :(得分:3)

  

Q1。 sub rsp,32

这是分配用于存储某些数据的空间。尽管它分配了32个字节,但是该代码仅使用该分配空间的前16个字节,即[rbp-8](0:edi)处的qword和[rbp-16](rdi)处的qword。

  

Q2。 lea rax,[rip + L_.str]和mov rdi,rax

lea正在获取存储在“代码”段中的字符串的地址。它已移至rdi,后者用作printf的参数之一。

  

Q3。 mov dword ptr [rbp-4],0 ... mov dword ptr [rbp-8],edi

它在[rbp-8]处存储由0:edi组成的64位小字节序值。我不确定为什么要这样做,因为以后再也不会从该qword加载它。

未优化的代码将其寄存器参数存储到内存中是正常的,调试信息可以告诉调试器在哪里寻找和修改它们,但是不清楚为什么clang将{{1}中的argc零扩展}到64位。

edi dword更有可能是单独的东西,因为如果编译器确实要存储零扩展的0,则编译器将在具有32位{{1 }},例如argcmov。可能这个额外的零是一个返回值临时变量,由于显式mov ecx, edi后来决定不使用它,而不是从mov [rbp-8], rcx的末尾掉落的隐式变量? (return 0;很特殊,我认为clang确实会为返回值创建一个内部临时变量。)

  

Q4 mov qword ptr [rbp-16],rsi ... mov rsi,qword ptr [rbp-16]

优化关闭了吗?它存储rsi,然后从[rbp-16]加载rsi。 rsi拥有argv函数arg(== {main)。 x86-64 System V ABI passes integer/pointer args in RDI, RSI, RDX, RCX, R8, R9, then on the stack

  

... mov rsi,qword ptr [rsi + 8]

这正在将main的内容装入rsi,作为&argv[0]的第二个arg。 (出于与main的第二个arg在rsi中相同的原因)。

x86-64 System V调用约定也是在调用没有FP args的varargs函数之前将AL清零的原因。

  

Q5。 mov dword ptr [rbp-20],eax

优化关闭了吗?它存储了printf的返回值,但是从不使用它。