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