Linux X86-64汇编和printf

4

我正在阅读一些Linux汇编手册,发现可以使用printf()函数的想法。出于调试原因,我需要将寄存器值以二进制形式输出到终端,但现在我只是尝试使用文本来测试该函数。

我遇到了困难,因为当我使用pushq而不是pushl时,出现了segfault错误。如何更改此程序以输出字符串和寄存器的二进制形式?

.data
input_prompt:
    .string "Hello, world!"

printf_format:
    .string "%5d "

printf_newline:
    .string "\n"

size:
    .long 0

.text
.globl main
main:
    pushq $input_prompt
    call  printf

    movl  $0, %eax
    ret

这段代码是由GCC编译的:

gcc tmp.S -o tmp

一个更详细的工作示例:使用GNU汇编器在x86_64中调用printf - undefined
1个回答

10

Linux(和Windows)x86-64调用约定的前几个参数不会在堆栈中,而是存储在寄存器中。

请参阅http://www.x86-64.org/documentation/abi.pdf (第20页)。

具体来说:

  1. 如果类别是MEMORY,则在堆栈上传递参数。
  2. 如果类别为INTEGER,使用序列%rdi、%rsi、%rdx、%rcx、%r8和%r9中的下一个可用寄存器。
  3. 如果类别为SSE,则使用下一个可用矢量寄存器,这些寄存器按顺序从%xmm0到%xmm7获取。
  4. 如果类别为SSEUP,则在上次使用的矢量寄存器中的下一个可用八字节块中传递八字节。
  5. 如果类别是X87、X87UP或COMPLEX_X87,则在内存中传递。

INTEGER类别是任何适合通用寄存器的内容,因此对于字符串指针也可以使用该类别。


3
Windows x64调用约定同样会将一些参数传递到寄存器中,但它与Linux调用约定不同(特别是请参阅"Parameter Passing"部分)。 - Matthew Slattery
你必须传递 eax = 1 来设置可变参数的数量,并对齐堆栈:https://dev59.com/-WPVa4cB1Zd3GeqP2yF4 || http://stackoverflow.com/questions/14000351/x86-64-linux-assembly-why-printf-with-float-format-string-work-only-with-rsp - Ciro Santilli OurBigBook.com
1
_EAX_将被设置为使用的向量寄存器的总数。如果没有使用向量寄存器(这可能是更正常的情况),_EAX_将为零。因此,_EAX_中的值取决于您传递的参数。 - Michael Petch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接