x86 Assembly, getting segmentation fault
The print_string subroutine is modifying the stack pointer without restoring it.
The subroutine main
has the following layout:
push ebp ;save the stack frame of the caller
mov ebp, esp ;save the stack pointer
<code for subroutine>
mov esp, ebp ;restore the stack pointer
pop ebp ;restore the caller's stack frame
ret ;return to address pushed onto the stack by call
Similarly, the print_string subroutine should have that same layout, saving the stack pointer and then restoring it before ret
ing. Any subroutines that use the stack should save and restore the stack pointer.
push ebp
mov ebp, esp
pusha
push msg
call printf ;should print "Hello"
add esp, 4
popa
mov esp, ebp
pop ebp
ret
Without saving the stack pointer and restoring it, the called subroutine modifies the stackpointer, where the call
instruction saved the return address. Consequently, when ret
is encountered, execution jumps to the wrong return address, therefore segfaulting. Read more on calling conventions and functions in assembly.
How do I fix Segmentation fault (core dumped) in assembly?
This isn't the best way to fix my issue, but it worked for me.
So I guess that when i gave space to each variable I was storing on the stack, I allocated 4 per each integer; hence the following code:
i_size = 4
j_size = 4
min_size = 4
temp_size = 4
v_size = 50*4
alloc = -(16+i_size+j_size+min_size+temp_size+v_size) & -16
dealloc = -alloc
i_s = 16
j_s = 20
min_s = 24
temp_s = 28
v_s = 32
In between the two reads from i_s, I increment j_s by 1, in a loop that runs 50 times. When I examine i_s using x/4x $x29+16
the second hex code was incremented by 1 on each iteration. It incremented every time that the code executed the instruction str x22, [x29, j_s]
so this made me realize what was wrong.
What ended up fixing my issue in the end, was that I changed the beginning block of code to this:
i_size = 8
j_size = 8
min_size = 8
temp_size = 8
v_size = 50*4
alloc = -(16+i_size+j_size+min_size+temp_size+v_size) & -16
dealloc = -alloc
i_s = 16
j_s = 24
min_s = 32
temp_s = 40
v_s = 48
so I ended up changing the size allocated to each integer from 4 to 8. Overkill, but I'm not sure what else to do to fix it.
Segmentation fault when calling x86 Assembly function from C program
Your function has no epilogue. You need to restore
%ebp
and pop the stack back to where it was, and thenret
. If that's really missing from your code, then that explains your segfault: the CPU will go on executing whatever garbage happens to be after the end of your code in memory.You clobber (i.e. overwrite) the
%ebx
register which is supposed to be callee-saved. (You mention following the x86 calling conventions, but you seem to have missed that detail.) That would be the cause of your next segfault, after you fixed the first one. If you use%ebx
, you need to save and restore it, e.g. withpush %ebx
after your prologue andpop %ebx
before your epilogue. But in this case it is better to rewrite your code so as not to use it at all; see below.movzbl
loads an 8-bit value from memory and zero-extends it into a 32-bit register. Here the parameters areint
so they are already 32 bits, so plainmovl
is correct. As it stands your function would give incorrect results for any arguments which are negative or larger than 255.You're using an unnecessary number of registers. You could move the first operand for the addition directly into
%eax
rather than putting it into%ebx
and adding it to zero. And on x86 it is not necessary to get both operands into registers before adding; arithmetic instructions have amem, reg
form where one operand can be loaded directly from memory. With this approach we don't need any registers other than%eax
itself, and in particular we don't have to worry about%ebx
anymore.
I would write:
.text
# Here, we define a function addition
.global addition
addition:
# Prologue:
push %ebp
movl %esp, %ebp
# load first argument
movl 8(%ebp), %eax
# add second argument
addl 12(%ebp), %eax
# epilogue
movl %ebp, %esp # redundant since we haven't touched esp, but will be needed in more complex functions
pop %ebp
ret
In fact, you don't need a stack frame for this function at all, though I understand if you want to include it for educational value. But if you omit it, the function can be reduced to
.text
.global addition
addition:
movl 4(%esp), %eax
addl 8(%esp), %eax
ret
Segmentation Fault in Assembly Language
I think the code fails here:
_start:
pushl $24
call profit
movl %eax, %ebx
movl $1, %eax
int $0x80
profit:
popl %ebx
popl %eax
So, you push $24
(4 bytes) and then call profit
, which pushes eip
and jumps to profit
. Then you pop the value of eip
into ebx
and the value $24
into eax
.
Then, in the end, if jg end
branches to end:
, then the stack won't hold a valid return address and ret
will fail. You probably need pushl %ebx
there too.
cmpl %ecx, %esi
jg end
pushl %ebx
ret
end:
mov %ecx, %eax
; `pushl %ebx` is needed here!
ret
Related Topics
How to Print the Nth (5Th) Line of Every File Preceded by the Filename Using Any Linux Tool
Sed: Matching on 2 Patterns on the Same Line
Differentiate Between Exit and Session Timeout
Django on Apache Wtih Mod_Wsgi (Linux) - 403 Forbidden
Comparison of Cat Pipe Awk Operation to Awk Command on a File
Jupyter Lab - Suppress Console Output
What Is Segment 00 in My Linux Executable Program (64 Bits)
Multiple -A with Greater Than/Less Than Break Bash Script
Overhead of Supporting Floating Point Arithmetic Inside the Linux Kernel
How to Make a Bash String of Command with Redirect and Pipe
Can Libpcap Reassemble Tcp Segments
Linux, Serial Port, Non-Buffering Mode
Why Can't Cuda's Examples Makefile Find the Cuda Libraries
How to Solve "Bash: Ls: Command Not Found"
How to Fix Numpy Dependencies Path on a Python 3.7.3 Script on Linux Frozen with Cx_Freeze 6.0B1
When Installing Rust Toolchain in Docker, Bash 'Source' Command Doesn't Work
Can Someone Explain How This "Shellshock" Code Works in Shell