0

I am using NASM on linux to write a basic assembly program that calls a function from the C libraries (printf). Unfortunately, I am incurring a segmentation fault while doing so. Commenting out the call to printf allows the program to run without error.

; 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
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • What is the calling convention for library functions, again? My guess is that you used the wrong one. – John Dvorak Mar 22 '13 at 16:46
  • In the book I am reading (which covers 32 bit assembly, not 64 bit), it simply says to push address of the string, call the function, clean the stack pointer. I thought text would be the only argument needed since printf searches a null byte to terminate. – user2177208 Mar 22 '13 at 16:56
  • 1
    The text string must end with a 0 byte! If it doesn't, how will `printf()` know where it ends? – Alexey Frunze Mar 22 '13 at 17:00
  • Woops. Thanks Alexey. I forgot to include that in the posted code. – user2177208 Mar 22 '13 at 17:03
  • I don't think you should fix bugs in the code posted in the question. This one, for example, is one possible reason for crashes. Does the code still crash after this fix? – Alexey Frunze Mar 22 '13 at 17:05
  • Yes. The reason for the crash was due to a combination of no terminating byte and something that I wasn't aware of, as pointed out by R.., x86-64 uses the registers for calling convention. – user2177208 Mar 22 '13 at 17:15
  • Your modified x86-64 code in the comments fixes your problem, though the comment on `mov rax,0` is completely wrong -- you're actually setting the number of XMM registers used to pass arguments to printf as 0. You actually only need `mov al,0`, as only the lowest 8 bits matter. – Chris Dodd Mar 22 '13 at 18:01

2 Answers2

3

x86_64 does not use the stack for the first 6 args. You need to load them in the proper registers. Those are:

rdi, rsi, rdx, rcx, r8, r9

The trick I use to remember the first two is to imagine the function is memcpy implemented as rep movsb,

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • Thank you. My book is on 32 bit assembly which does place the arguments on the stack. – user2177208 Mar 22 '13 at 17:15
  • 4
    In addition, since `printf` is a varargs function, you need to set `%al` to the number of XMM registers used for arguments -- 0 here. – Chris Dodd Mar 22 '13 at 17:57
0

You're calling a varargs function -- printf expects a variable number of arguments and you have to account for that in the argument stack. See here: http://www.csee.umbc.edu/portal/help/nasm/sample.shtml#printf1

K Scott Piel
  • 4,320
  • 14
  • 19