printf arg list的gcc汇编器输出

时间:2013-06-23 07:58:42

标签: gcc printf command-line-arguments x86-64 gas

上个学期我在系统级编程课程中学习了MIPS汇编,现在一直在研究英特尔和AMD架构。

我无法在GAS中编写一个简单的x86_64程序来调用printf并打印argc和argv [0-4]。为了帮助我理解如何正确地完成它,我使用“gcc -S”来查看C源文件“test.c”的汇编程序:

#include <stdio.h>
int main (int argc, char * argv[]) {
    printf("%d,%s,%s,%s,%s,%s\n", argc, argv[0], argv[1], argv[2], argv[3], argv[4]);
return 0;
}

“gcc -S -masm = intel test.c”的输出是:

    .file   "test.c"
    .intel_syntax noprefix
    .section    .rodata
.LC0:
    .string "%d,%s,%s,%s,%s,%s\n"
    .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, 32
    mov DWORD PTR [rbp-4], edi
    mov QWORD PTR [rbp-16], rsi
    mov rax, QWORD PTR [rbp-16]
    add rax, 32
    mov rsi, QWORD PTR [rax]
    mov rax, QWORD PTR [rbp-16]
    add rax, 24
    mov r8, QWORD PTR [rax]
    mov rax, QWORD PTR [rbp-16]
    add rax, 16
    mov rdi, QWORD PTR [rax]
    mov rax, QWORD PTR [rbp-16]
    add rax, 8
    mov rcx, QWORD PTR [rax]
    mov rax, QWORD PTR [rbp-16]
    mov rdx, QWORD PTR [rax]
    mov eax, DWORD PTR [rbp-4]
    mov QWORD PTR [rsp], rsi
    mov r9, r8
    mov r8, rdi
    mov esi, eax
    mov edi, OFFSET FLAT:.LC0
    mov eax, 0
    call    printf
    mov eax, 0
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   main, .-main
    .ident  "GCC: (GNU) 4.7.2 20121109 (Red Hat 4.7.2-8)"
    .section    .note.GNU-stack,"",@progbits

说实话,我认为我完全不了解第18-38行所发生的事情。对我来说,看起来gcc在[rbp-4]和[rbp-16]存储指向argc和argv [0]的指针,然后将[rbp-16]作为基点加载到rax中(指向argv [0]的指针) ),并添加8,16,24,...使rax指向argv [1,2,3,...],然后将该地址加载到相应的寄存器中以传递给printf。

通过这种解释,我能够充分理解命令行参数如何传递给main()以便能够修复我的GAS代码:

.intel_syntax noprefix
.globl  main

.data
fmt:    .asciz  "%d,%s,%s,%s,%s,%s\n"

.text
main:
    push    rbp
    mov     rbp, rsp

    mov     rdx, QWORD PTR [rsi]
    mov     rcx, QWORD PTR [rsi+8]
    mov     r8, QWORD PTR [rsi+16]
    mov     r9, QWORD PTR [rsi+24]
    push    [rsi+32]
    mov     rsi, rdi
    mov     rdi, offset fmt
    xor     rax, rax
    call    printf

return:
    mov     rsp, rbp
    pop     rbp
    xor     rax, rax
    ret

这产生与test.c相同的输出,以及gcc生成的test.s.所以我的问题是......我做的方式有什么问题吗?如果没有,为什么gcc会产生如此复杂的方式来做这么简单的事情?也许这只是编译器解释数组使用的方式?

我认为我的方法在技术上是正确的,因为它产生相同的输出,但我想确保它是一种“可接受的”方式。

0 个答案:

没有答案