从程序集调用C函数(printf)时出现SEGFULT

从程序集调用C函数(printf)时出现SEGFULT,c,linux,assembly,x86-64,calling-convention,C,Linux,Assembly,X86 64,Calling Convention,我正在linux上使用NASM编写一个基本汇编程序,从C库(printf)调用函数。不幸的是,我在这样做时遇到了分割错误。注释掉对printf的调用可以让程序无误地运行 ; Build using these commands: ; nasm -f elf64 -g -F stabs <filename>.asm ; gcc <filename>.o -o <filename> ; SECTION .bss ; Section contain

我正在linux上使用NASM编写一个基本汇编程序,从C库(printf)调用函数。不幸的是,我在这样做时遇到了分割错误。注释掉对printf的调用可以让程序无误地运行

; Build using these commands:
;   nasm -f elf64 -g -F stabs <filename>.asm 
;   gcc <filename>.o -o <filename>
;

SECTION .bss    ; Section containing uninitialized data

SECTION .data   ; Section containing initialized data

  text db "hello world",10 ; 

SECTION .text   ; Section containing code


global main

extern printf

;-------------
;MAIN PROGRAM BEGINS HERE
;-------------

main:



      push rbp

      mov rbp,rsp

      push rbx

      push rsi

      push rdi ;preserve registers

      ****************


      ;code i wish to execute

      push text ;pushing address of text on to the stack
      ;x86-64 uses registers for first 6 args, thus should have been:
      ;mov rdi,text (place address of text in rdi)
      ;mov rax,0 (place a terminating byte at end of rdi)

      call printf ;calling printf from c-libraries

      add rsp,8 ;reseting the stack to pre "push text"

      **************  

      pop rdi ;preserve registers

      pop rsi

      pop rbx

      mov rsp,rbp

      pop rbp

      ret
;使用以下命令生成:
;   nasm-f elf64-g-f stabs.asm
;   gcc.o-o
;
第三节bss;包含未初始化数据的节
第二节数据;包含初始化数据的节
文本数据库“你好,世界”,10;
第节.案文;包含代码的节
全球主要
外部打印
;-------------
;主程序从这里开始
;-------------
主要内容:
推动rbp
mov rbp,rsp
推送rbx
推挤性rsi
推动rdi;保存寄存器
****************
;我希望执行的代码
推送文本;将文本地址推送到堆栈上
;x86-64为前6个参数使用寄存器,因此应该是:
;mov rdi,文本(文本在rdi中的位置地址)
;mov rax,0(在rdi末尾放置一个终止字节)
调用printf;从c库调用printf
加上rsp,8;将堆栈重置为预“推送文本”
**************  
流行性rdi;保存寄存器
流行性rsi
流行音乐
mov rsp,rbp
流行限制性商业惯例
ret

您正在调用一个varargs函数——printf需要一个数量可变的参数,您必须在参数堆栈中说明这一点。请参见此处:

您正在调用一个varargs函数——printf需要一个数量可变的参数,您必须在参数堆栈中说明这一点。请参见此处:

x86_64不将堆栈用于前6个参数。您需要将它们加载到正确的寄存器中。这些是:

rdi, rsi, rdx, rcx, r8, r9

我用来记住前两个参数的诀窍是将函数
memcpy
实现为
rep movsb

x86\u 64不将堆栈用于前6个参数。您需要将它们加载到正确的寄存器中。这些是:

rdi, rsi, rdx, rcx, r8, r9

我用来记住前两个函数的诀窍是将函数
memcpy
实现为
rep movsb

库函数的调用约定又是什么?我猜你用错了。在我正在读的书中(涉及32位汇编,而不是64位),它只是说推送字符串的地址,调用函数,清除堆栈指针。我认为文本是唯一需要的参数,因为printf搜索空字节来终止。文本字符串必须以0字节结束!如果不知道,怎么知道它的结尾呢。谢谢阿列克西。我忘了在发布的代码中包含这一点。我认为你不应该修复问题中发布的代码中的错误。例如,这一点可能是导致崩溃的原因之一。修复后代码是否仍然崩溃?库函数的调用约定是什么?我猜你用错了。在我正在读的书中(涉及32位汇编,而不是64位),它只是说推送字符串的地址,调用函数,清除堆栈指针。我认为文本是唯一需要的参数,因为printf搜索空字节来终止。文本字符串必须以0字节结束!如果不知道,怎么知道它的结尾呢。谢谢阿列克西。我忘了在发布的代码中包含这一点。我认为你不应该修复问题中发布的代码中的错误。例如,这一点可能是导致崩溃的原因之一。修复后代码是否仍然崩溃?谢谢。我的书是关于32位汇编的,它将参数放在堆栈上。此外,由于
printf
是一个varargs函数,您需要将
%al
设置为用于参数的XMM寄存器的数量--此处为0。谢谢。我的书是关于32位汇编的,它将参数放在堆栈上。此外,由于
printf
是一个varargs函数,因此需要将
%al
设置为用于参数的XMM寄存器的数量——此处为0。