The following program causing a segmentation fault and I don't seem to understand why:
//something.c
int somefunc3();
void somefunc2();
void* globalptr;
void somefunc1(void* regs)
{
globalptr = regs;
somefunc2();
}
int foo()
{
return somefunc3();
}
int main(void)
{
show_all_registers();
foo();
show_all_registers();
}
asm:
//something1.asm
extern _somefunc1
global _somefunc2
global _somefunc3
section .text
%macro RESTORE_REGISTERS 0
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
%endmacro
%macro SAVE_REGISTERS 0
push rcx
push rcx
push rcx
push rcx
push rcx
push rcx
push rcx
push rcx
push rcx
push rcx
push rcx
push rcx
push rcx
push rcx
push rcx
push rcx
%endmacro
_somefunc3:
push rbp
mov rbp, rsp
SAVE_REGISTERS
mov rdi, rsp
sub rsp,8
call _somefunc1
add rsp,8
pop rbp
ret
_somefunc2:
push rbp
mov rbp, rsp
RESTORE_REGISTERS
pop rbp
ret
few notes:
Please don't try to understand what this program does because you won't find anything that makes sense. This is just a user mode app which I created in order to understand something.
show_all_registers is just a function that prints out to the screen all of the 64 bit registers.
Here's what happens before it crashes:
64 Bit registers:
RAX=10767ad00, RCX=1, RDX=10767ab70, RBX=0, RSP=7fff58585bd0, RBP=7fff58585bd0, RSI=20000000200, RDI=7
Segmentation fault: 11
Using GDB it seems that the crash occurs on somefunc2 (When restoring the registers)
I think that it has something to do with stack alignment or the epilogues & epilogues I wrote for the ASM functions. Still kinda newbie so it is most likely something silly.
thanks
Your function epilogues are incorrect. You're missing the mov rsp, rbp, so your stack frame is totally off at return time.
A proper function would be:
push rbp
mov rbp, rsp
sub rsp, [size of local variables]
...
mov rsp, rbp
pop rbp
ret
Or you can simplify with the LEAVE instruction:
push rbp
mov rbp, rsp
sub rsp, [size of local variables]
...
leave
ret
Related
Here is my code: (details at the end)
extern timerh
isr_timer:
push rax
push rdi
push rdx
push rcx
push rsi
push rbx
push rsp
push rbp
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15
call timerh
pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
pop rbp
pop rsp
pop rbx
pop rsi
pop rcx
pop rdx
pop rdi
pop rax
iretq
void timerh(uint64_t t) {
print("timer\n");
*EOI = 0;
return;
}
the acpi() functions starts the timer
acpi();
print("testing\n");
So if I delete the print("testing"), everything works and the timerh prints consistently, however when the print("testing") is there, it doesnt work, it either gives a GPF or a page fault. The timer might run a couple times but then it errors
I know the x64 calling convention, first four arguments are in rcx, rdx, r8, r9, rest are on the stack. But my question is how push these arguments?
call_func PROC
push rbp
mov rbp, rsp
mov rbx, rcx ; move C function address to rbx
mov rcx, 1 ; some dummy value
mov rdx, 2 ; some dummy value
mov r8, 3 ; some dummy value
mov r9, 4 ; some dummy value
; and now I want to push fifth argument, but how?
call rbx ; call the function
mov rsp, rbp
pop rbp
ret
call_func ENDP
I have tried mov QWORD PTR [rsp + 20h], 1 but when returning form this asm function the RIP register is set to weird value, like 0x0000000000000001. I know that the RIP register is instruction pointer, but why it is modifying it?
I have tried one more thing, let the function take 6 arguments and when I pass sixth argument like mov QWORD PTR [rsp + 28h], 1 the app is fine, sixth argument is passed, fifth has weird value.
As Jester said, before pushing arguments I need to allocate space for these arguments including shadow space.
Final working code:
call_func PROC
push rbp
mov rbp, rsp
sub rsp, 32 ; allocate shadow space 'padding'
sub rsp, 16 ; allocate space for fifth and sixth argument
mov r11, rcx ; move C function address to r11
mov rcx, 1 ; some dummy value
mov rdx, 2 ; some dummy value
mov r8, 3 ; some dummy value
mov r9, 4 ; some dummy value
mov QWORD PTR [rsp + 20h], 5 ; push fifth argument
mov QWORD PTR [rsp + 28h], 6 ; push sixth argument
call r11 ; call the function
mov rsp, rbp
pop rbp
ret
call_func ENDP
I am trying to understand how a variable sized static array work internally:
Following is a fixed size static array in C and its Assembly equivalent;
int main()
{
int arr[2] = {3};
}
================
main:
push rbp
mov rbp, rsp
mov QWORD PTR [rbp-8], 0
mov DWORD PTR [rbp-8], 2
mov eax, 0
pop rbp
ret
However a variable sized array is shown below
int main()
{
int varSize ;
int Arr[varSize];
}
=================
main:
push rbp
mov rbp, rsp
sub rsp, 32
mov rax, rsp
mov rcx, rax
mov eax, DWORD PTR [rbp-4]
movsx rdx, eax
sub rdx, 1
mov QWORD PTR [rbp-16], rdx
movsx rdx, eax
mov r8, rdx
mov r9d, 0
movsx rdx, eax
mov rsi, rdx
mov edi, 0
cdqe
lea rdx, [0+rax*4]
mov eax, 16
sub rax, 1
add rax, rdx
mov edi, 16
mov edx, 0
div rdi
imul rax, rax, 16
sub rsp, rax
mov rax, rsp
add rax, 3
shr rax, 2
sal rax, 2
mov QWORD PTR [rbp-24], rax
mov rsp, rcx
mov eax, 0
leave
ret
I am seeing a whole lot of assembly instructions if I declare a variable sized array. Can some one explain how is this flexibility of variable size achieved?
Same mechanism as alloca() - allocate memory by decreasing the stack pointer, with the assumption that the stack is big enough and/or the OS will grow it as needed.
There might be a bit of an issue when the requested size is over a memory page and the stack is near its end. Normally, the OS grows the stack by setting up a guard page at the stack top and watching for faults in that area, but that assumes that the stack grows more or less sequentially (by pushes and function calls). If the decreased stack pointer overshoots the guard page, it might end up pointing at a bogus location. I'm not sure what does the compiler do about that possibility.
I am trying to write a "strcat" function in assembly and can't get the values in the memory I pass it to change. My tests are crashing and I don't understand why. I can't seem to find any good documentation on x86_64 assembly in an easy to digest manner either.
global _ft_strcat
_ft_strcat:
push rbx
push rdx
mov rbx, rsi
mov rdx, rdi
parse:
cmp byte [rdx], 0
je concat
inc rdx
jmp parse
concat:
cmp BYTE[rbx], 0
je finish
mov dl, BYTE[rbx]
mov BYTE[rdx], dl
inc rdx
inc rbx
jmp concat
finish:
mov BYTE[rdx], 0
mov rax, rdi
pop rdx
pop rbx
ret
The above is the function I am trying to write and below is my test.
int main(void)
{
char buffer[50] = "Hello, ";
ft_strcat(buffer, "World!");
printf("%s\n", buffer);
return (0);
}
I left out things such as includes and my header because that is not relevant to the question from what I can see. I ran this through a debugger and noticed that at the end of my function, the string pointed to by the rdi register has not changed, but I do go through the loop in the concat label and it looks like the values being extracted from the string being pointed to by rsi is indeed being copied into the dl register.
Your pushes and pops don't match so your routine changes rbp and rbx contrary to the ABI requirement to preserve them.
My problem was my lack of understand how I was manipulating the rdx register's lowest 8-bits. By inserting my character into dl, its value updated the overall value of rdx, which meant that I was not actually concatenating the string I had, but I was writing into regions of memory I didn't know I was writing into.
The code now looks like this
global _ft_strcat
_ft_strcat:
push rbx
push rdx
push rcx
xor rcx, rcx
mov rbx, rsi
mov rdx, rdi
parse:
cmp byte [rdx], 0
je concat
inc rdx
jmp parse
concat:
cmp BYTE[rbx], 0
je finish
mov cl, BYTE[rbx]
mov BYTE[rdx], cl
inc rdx
inc rbx
jmp concat
finish:
mov BYTE[rdx], 0
pop rcx
pop rdx
pop rbx
mov rax, rdi
ret
You will notice the addition of the Rex register and the use of its lower 8 bits for copying bytes over.
section .data
text db 'Put a number',10,0
scanform db '%d'
number dw 0
section .text
extern printf,scanf
global main
main:
push rbp
mov rbp,rsp
push rdi
push rsi
push rbx
mov rdi,text
mov rax,0
call printf
mov rsi,number
mov rdi,scanform
mov rax,0
call scanf
pop rbx
pop rsi
pop rdi
ret
This is my code I write a other codes all day and I do not have problem with these but now when I call scanf, write program received signal SIGSEV, segfault... Specified first and last line in different files. I do not understand this message can someone help me?
You have the following issues:
You forgot to pop rbp.
You misalign the stack which needs to be 16 byte aligned.
You do not zero terminate your format string (thanks to Paul for pointing this out).
You use %d which writes a 4 byte integer but you only allocated 2 bytes with dw.
It is recommended to align integers to 4 bytes.
A possible fixed version:
section .data
number dd 0
text db 'Put a number',10,0
scanform db '%d', 0
section .text
extern printf,scanf
global main
main:
push rbp
mov rbp,rsp
push rdi
push rsi
push rbx
push rbx ; for alignment
mov rdi,text
mov rax,0
call printf
mov rsi,number
mov rdi,scanform
mov rax,0
call scanf
pop rbx
pop rbx
pop rsi
pop rdi
pop rbp
ret
Since rsi and rdi are caller-saved registers and rbx is not touched, you can simplify the code. I also changed to xor zeroing and rip-relative addressing as follows:
section .data
number dd 0
text db 'Put a number',10,0
scanform db '%d', 0
section .text
extern printf,scanf
global main
main:
push rbp
lea rdi, [rel text]
xor eax, eax
call printf
lea rsi, [rel number]
lea rdi, [rel scanform]
xor eax, eax
call scanf
pop rbp
ret