I've been trying to learn 64-bit assembly on both Mac-OS and Windows using NASM.
My code is
extern _printf
section .data
msg db "Hello World!", 10, 0
section .text
global _main
_main:
mov rax, 0
mov rdi, msg
call _printf
mov rax, 0x2000001
mov rdi, 0
syscall
and I compile it with
nasm -f macho64 -o main.o main.asm
gcc -o main main.o
While trying to call _printf, I got the error
Segmentation fault: 11
When I remove the call to _printf, my code runs fine.
Why does the call to _printf cause a segmentation fault?
I have found the ABI Calling Convention here, but had no luck successfully calling a C-function.
I would expect Hello World! to be printedd, however I get 'Segmentation Fault: 11' instead.
~~You need to setup a stack frame before calling _printf
TL;DR: The System V AMD64 ABI requires the stack-pointer to be 16-byte-aligned. By the time of calling _printf, the stack-pointer is misaligned by 8 bytes.
Debugging the binary with LLDB gives:
frame #0: 0x00007fff527d430a libdyld.dylib`stack_not_16_byte_aligned_error
MacOS uses the System V AMD64 ABI and therefore relies on 16-byte alignment for the stack-pointer (see this question), in short this means the stack-pointer (rsp) should always be divisible by 16 when calling a function.
By the time of calling _printf, the stack-pointer (rsp) is misaligned by 8 bytes. How did this come?
I found the answer on this page, calling the _main function pushes the return address (8 bytes) on the stack and therefore misaligns it.
My initial idea - the setup of the stack frame - pushed another address on the stack and therefore rsp was divisible by 16 again.
However an easier solution would be just sub rsp, 8 as suggested by Margaret Bloom
Change your code to:
extern _printf
section .data
msg: db "Hello World!", 10, 0
section .text
global _main
_main:
;; Fix the stack alignment
sub rsp, 8
mov rax, 0
mov rdi, msg
call _printf
mov rax, 0x2000001
mov rdi, 0
syscall
Tested on macOS 10.13.6
Related
When compiling below code:
global main
extern printf, scanf
section .data
msg: db "Enter a number: ",10,0
format:db "%d",0
section .bss
number resb 4
section .text
main:
mov rdi, msg
mov al, 0
call printf
mov rsi, number
mov rdi, format
mov al, 0
call scanf
mov rdi,format
mov rsi,[number]
inc rsi
mov rax,0
call printf
ret
using:
nasm -f elf64 example.asm -o example.o
gcc -no-pie -m64 example.o -o example
and then run
./example
it runs, print: enter a number:
but then crashes and prints:
Segmentation fault (core dumped)
So printf works fine but scanf not.
What am I doing wrong with scanf so?
Use sub rsp, 8 / add rsp, 8 at the start/end of your function to re-align the stack to 16 bytes before your function does a call.
Or better push/pop a dummy register, e.g. push rdx / pop rcx, or a call-preserved register like RBP you actually wanted to save anyway. You need the total change to RSP to be an odd multiple of 8 counting all pushes and sub rsp, from function entry to any call.
i.e. 8 + 16*n bytes for whole number n.
On function entry, RSP is 8 bytes away from 16-byte alignment because the call pushed an 8-byte return address. See Printing floating point numbers from x86-64 seems to require %rbp to be saved,
main and stack alignment, and Calling printf in x86_64 using GNU assembler. This is an ABI requirement which you used to be able to get away with violating when there weren't any FP args for printf. But not any more.
See also Why does the x86-64 / AMD64 System V ABI mandate a 16 byte stack alignment?
To put it another way, RSP % 16 == 8 on function entry, and you need to ensure RSP % 16 == 0 before you call a function. How you do this doesn't matter. (Not all functions will actually crash if you don't, but the ABI does require/guarantee it.)
gcc's code-gen for glibc scanf now depends on 16-byte stack alignment
even when AL == 0.
It seems to have auto-vectorized copying 16 bytes somewhere in __GI__IO_vfscanf, which regular scanf calls after spilling its register args to the stack1. (The many similar ways to call scanf share one big implementation as a back end to the various libc entry points like scanf, fscanf, etc.)
I downloaded Ubuntu 18.04's libc6 binary package: https://packages.ubuntu.com/bionic/amd64/libc6/download and extracted the files (with 7z x blah.deb and tar xf data.tar, because 7z knows how to extract a lot of file formats).
I can repro your bug with LD_LIBRARY_PATH=/tmp/bionic-libc/lib/x86_64-linux-gnu ./bad-printf, and also it turns out with the system glibc 2.27-3 on my Arch Linux desktop.
With GDB, I ran it on your program and did set env LD_LIBRARY_PATH /tmp/bionic-libc/lib/x86_64-linux-gnu then run. With layout reg, the disassembly window looks like this at the point where it received SIGSEGV:
│0x7ffff786b49a <_IO_vfscanf+602> cmp r12b,0x25 │
│0x7ffff786b49e <_IO_vfscanf+606> jne 0x7ffff786b3ff <_IO_vfscanf+447> │
│0x7ffff786b4a4 <_IO_vfscanf+612> mov rax,QWORD PTR [rbp-0x460] │
│0x7ffff786b4ab <_IO_vfscanf+619> add rax,QWORD PTR [rbp-0x458] │
│0x7ffff786b4b2 <_IO_vfscanf+626> movq xmm0,QWORD PTR [rbp-0x460] │
│0x7ffff786b4ba <_IO_vfscanf+634> mov DWORD PTR [rbp-0x678],0x0 │
│0x7ffff786b4c4 <_IO_vfscanf+644> mov QWORD PTR [rbp-0x608],rax │
│0x7ffff786b4cb <_IO_vfscanf+651> movzx eax,BYTE PTR [rbx+0x1] │
│0x7ffff786b4cf <_IO_vfscanf+655> movhps xmm0,QWORD PTR [rbp-0x608] │
>│0x7ffff786b4d6 <_IO_vfscanf+662> movaps XMMWORD PTR [rbp-0x470],xmm0 │
So it copied two 8-byte objects to the stack with movq + movhps to load and movaps to store. But with the stack misaligned, movaps [rbp-0x470],xmm0 faults.
I didn't grab a debug build to find out exactly which part of the C source turned into this, but the function is written in C and compiled by GCC with optimization enabled. GCC has always been allowed to do this, but only recently did it get smart enough to take better advantage of SSE2 this way.
Footnote 1: printf / scanf with AL != 0 has always required 16-byte alignment because gcc's code-gen for variadic functions uses test al,al / je to spill the full 16-byte XMM regs xmm0..7 with aligned stores in that case. __m128i can be an argument to a variadic function, not just double, and gcc doesn't check whether the function ever actually reads any 16-byte FP args.
I'm just getting started with assembly and I wanted to create a simple program that adds two numbers and prints the result
This is what I have so far:
.globl main
.type main, #function
main:
movl $14, %eax
movl $10, %ebx
add %eax, %ebx
call printf
From my understanding here is what's happening line by line
Line 1: I'm creating a label main that can be accessed by the linker
Line 2: I'm specifying the type of label main to a function
Line 3: I begin my definition of main
Line 4: I store the numeric value 14 into the general register eax
Line 5: I store the numeric value 10 into the general register ebx
Line 6: I add the values at eax and ebx and store the result in ebx
Line 7: I call the function printf(here's where I get confused)
How do I specify what value at which register gets printed?
Also, how do I complete this program? Currently when run, the program results in a segmentation fault.
SECTION .data
extern printf
global main
fmt:
db "%d", 10, 0
SECTION .text
main:
mov eax, 14
mov ebx, 10
add eax, ebx
push eax
push fmt
call printf
mov eax, 1
int 0x80
Unfortunately I don't know which compiler/assembler you are using, and I'm not familiar with at&t syntax so I have given you a working example in Intel style x86 for Nasm.
$ nasm -f elf32 test.s -o test.o
$ gcc test.o -m32 -o test
$ ./test
24
In order to use printf you need to actually push the arguments for it onto the stack, I do this here in reverse order (push the last arguments first):
push eax
push fmt
EAX contains the result of add eax, ebx and the label 'fmt' is an array of chars: "%d\n\0" (%d format, newline, null terminator).
After calling printf you need to actually exit your program with the exit system call, otherwise (at least for me) the program will segfault AFTER printf even though it worked and you won't see the result.
So these two lines:
mov eax, 1
int 0x80
are performing the sys_exit system call by placing the ordinal of exit on x86 (1) into EAX, and then invoking interrupt 0x80, this exits the program cleanly.
I'm just trying to load the value of myarray[0] to eax:
.text
.data
# define an array of 3 words
array_words: .word 1, 2, 3
.globl main
main:
# assign array_words[0] to eax
mov $0, %edi
lea array_words(,%edi,4), %eax
But when I run this, I keep getting seg fault.
Could someone please point out what I did wrong here?
It seems the label main is in the .data section.
It leads to a segmentation fault on systems that doesn't allow to execute code in the .data section. (Most modern systems map .data with read + write but not exec permission.)
Program code should be in the .text section. (Read + exec)
Surprisingly, on GNU/Linux systems, hand-written asm often results in an executable .data unless you're careful to avoid that, so this is often not the real problem: See Why data and stack segments are executable? But putting code in .text where it belongs can make some debugging tools work better.
Also you need to ret from main or call exit (or make an _exit system call) so execution doesn't fall off the end of main into whatever bytes come next. See What happens if there is no exit system call in an assembly program?
You need to properly terminate your program, e.g. on Linux x86_64 by calling the sys_exit system call:
...
main:
# assign array_words[0] to eax
mov $0, %edi
lea array_words(,%edi,4), %eax
mov $60, %rax # System-call "sys_exit"
mov $0, %rdi # exit code 0
syscall
Otherwise program execution continues with the memory contents following your last instruction, which are most likely in all cases invalid instructions (or even invalid memory locations).
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
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,
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
Basically, I read through parts of http://www.nasm.us/links/unix64abi and at page 29, it shows the initial process stack of a C program.
My question is: I'm trying to interface with glibc from x86-64 nasm and based on what the above shows, argc should be at rsp. So the following code should print argc:
[SECTION .data]
PrintStr: db "You just entered %d arguments.", 10, 0
[SECTION .bss]
[SECTION .text]
extern printf
global main
main:
mov rax, 0 ; Required for functions taking in variable no. of args
mov rdi, PrintStr
mov rsi, [rsp]
call printf
ret
But it doesn't. Can someone enlighten me if I have made any mistakes in my code or tell me what the actual stack structure is?
Thanks!
UPDATE: I just randomly tried some offsets and changing the "mov rsi, [rsp]" to "mov rsi, [rsp+28]" did the trick.
But this means that the stack structure shown is wrong. Does anyone know what the initial stack layout is for an x86-64 elf? An equivalent of http://asm.sourceforge.net/articles/startup.html would be really nice.
UPDATE 2:
I left out how I build this code. I do it by:
nasm -f elf64 -g <filename>
gcc <filename>.o -o <outputfile>
The initial stack layout contains argc at the stack pointer, followed by the array char *argv[], not a pointer to it like main receives. Therefore, to call main, you need to do something like:
pop %rdi
mov %rsp,%rsi
call main
In reality there is usually a wrapper function that calls main, rather than the startup code doing it directly.
If you want to simply print argv[0], you could do something like:
pop %rdi
pop %rdi
call puts
xor %edi,%edi
jmp exit