Segmentation-Fault Error Happening with Assembly Code Program

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 reting. 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

  1. Your function has no epilogue. You need to restore %ebp and pop the stack back to where it was, and then ret. 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.

  2. 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. with push %ebx after your prologue and pop %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.

  3. movzbl loads an 8-bit value from memory and zero-extends it into a 32-bit register. Here the parameters are int so they are already 32 bits, so plain movl is correct. As it stands your function would give incorrect results for any arguments which are negative or larger than 255.

  4. 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 a mem, 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



Leave a reply



Submit