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

Я использую 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

person user2177208    schedule 22.03.2013    source источник
comment
Опять же, каково соглашение о вызовах библиотечных функций? Я предполагаю, что вы использовали не тот.   -  person John Dvorak    schedule 22.03.2013
comment
В книге, которую я читаю (которая охватывает 32-битную сборку, а не 64-битную), просто говорится, что нужно нажать адрес строки, вызвать функцию, очистить указатель стека. Я думал, что текст будет единственным необходимым аргументом, поскольку printf ищет нулевой байт для завершения.   -  person user2177208    schedule 22.03.2013
comment
Текстовая строка должна заканчиваться нулевым байтом! Если этого не произойдет, как printf() узнает, где это закончится?   -  person Alexey Frunze    schedule 22.03.2013
comment
Вупс. Спасибо, Алексей. Я забыл включить это в опубликованный код.   -  person user2177208    schedule 22.03.2013
comment
Я не думаю, что вам следует исправлять ошибки в коде, опубликованном в вопросе. Это, например, одна из возможных причин сбоев. После этого исправления код по-прежнему дает сбой?   -  person Alexey Frunze    schedule 22.03.2013
comment
да. Причина сбоя была связана с комбинацией отсутствия завершающего байта и чего-то, о чем я не знал, как указано R .., x86-64 использует регистры для соглашения о вызовах.   -  person user2177208    schedule 22.03.2013
comment
Ваш измененный код x86-64 в комментариях решает вашу проблему, хотя комментарий к mov rax,0 совершенно неверен - вы фактически устанавливаете количество регистров XMM, используемых для передачи аргументов printf равным 0. На самом деле вам нужно только mov al,0, только самые младшие 8 бит имеют значение.   -  person Chris Dodd    schedule 22.03.2013


Ответы (2)


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

rdi, rsi, rdx, rcx, r8, r9

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

person R.. GitHub STOP HELPING ICE    schedule 22.03.2013
comment
Спасибо. Моя книга посвящена 32-битной сборке, которая помещает аргументы в стек. - person user2177208; 22.03.2013
comment
Кроме того, поскольку printf является функцией varargs, вам необходимо установить %al на количество регистров XMM, используемых для аргументов - здесь 0. - person Chris Dodd; 22.03.2013

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

person K Scott Piel    schedule 22.03.2013