Segfault при вызове функции C (printf) из Assembly

Я использую NASM в Linux для написания базовой программы сборки, которая вызывает функцию из библиотек 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

3 ответа

x86_64 не использует стек для первых 6 аргументов. Вам нужно загрузить их в соответствующие регистры. Это:

rdi, rsi, rdx, rcx, r8, r9

Хитрость, которую я использую, чтобы запомнить первые два, - представить себе, что функция memcpy реализовано как rep movsb,

Вы должны быть знакомы с используемыми соглашениями о вызовах. Linux на AMD64 использует System V AMD64 ABI. Из этого документа мы узнаем, что:

  • целочисленные аргументы передаются в rdi, rsi, rdx, rcx, r8 и r9
  • Поплавки передаются от xmm0 до xmm7
  • для функций varargs количество используемых регистров SSE помещается в rax

Так что для звонка

printf ("Hello World\n");

У тебя есть

.section .rodata
format db "Hello World", 10, 0

.section .text
my_function:

    ; with RSP 16-byte aligned    
    mov   edi, format             ; or in PIC code: lea rdi, [rel format]
                      ; mov rsi, 2nd arg  if any
    xor   eax, eax                ; no FP args
    call  printf

Обратите внимание, что 0 терминатор в строке: строки C имеют неявную длину и заканчиваются 0 байт.

Вы вызываете функцию varargs - printf ожидает переменное количество аргументов, и вы должны учитывать это в стеке аргументов. Смотрите здесь: http://www.csee.umbc.edu/portal/help/nasm/sample.shtml

Другие вопросы по тегам