Segmentation Fault in Assembly Language - linux

I am learning AT&T x86 assembly language. I am trying to write an assembly program which takes an integer n, and then return the result (n/2+n/3+n/4). Here is what I have done:
.text
.global _start
_start:
pushl $24
call profit
movl %eax, %ebx
movl $1, %eax
int $0x80
profit:
popl %ebx
popl %eax
mov $0, %esi
movl $4, %ebp
div %ebp
addl %eax, %esi
movl %ecx, %eax
movl $3, %ebp
div %ebp
addl %eax, %esi
movl %ecx, %eax
movl $2, %ebp
div %ebp
addl %eax, %esi
movl %esi, %eax
cmpl %ecx, %esi
jg end
pushl %ebx
ret
end:
mov %ecx, %eax
ret
The problem is I am getting segmentation fault. Where is the problem?

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

You do not appear to be doing function calls correctly. You need to read and understand the x86 ABI (32-bit, 64-bit) particularly the "calling convention" sections.
Also, this is not your immediate problem, but: Don't write _start, write main as if this were a C program. When you start doing something more complicated, you will want the C library to be available, and that means you have to let it initialize itself. Relatedly, do not make your own system calls; call the wrappers in the C library. That insulates you from low-level changes in the kernel interface, ensures that errno is available, and so on.

you use ecx without ever explicitly initializing it (I'm not sure if Linux will guarantee the state of ecx when the process starts - looks like it's 0 in practice if not by rule)
when the program takes the jg end jump near the end of the procedure, the return address is no longer on the stack, so ret will transfer control to some garbage address.

Your problem is that you pop the return address off of the stack and when you branch to end you don't restore it. A quick fix is to add push %ebx there as well.
What you should do is modify your procedure so it uses the calling convention correctly. In Linux, the caller function is expected to clean the arguments from the stack, so your procedure should leave them where they are.
Instead of doing this to get the argument and then restoring the return address later
popl %ebx
popl %eax
You should do this and leave the return address and arguments where they are
movl 4(%esp), %eax
and get rid of the code that pushes the return address back onto the stack. You then should add
subl $4, %esp
after the call to the procedure to remove the argument from the stack. It's important to follow this convention correctly if you want to be able to call your assembly procedures from other languages.

It looks to me like you have a single pushl before you call profit and then the first thing that profit does is to do two popl instructions. I would expect that this would pop the value you pushed onto the stack as well as the return code so that your ret would not work.
push and pop should be the same number of times.
call pushes the return address onto the stack.

Related

what is the purpose of "movl $0, %ebx" or getting 0 into ebx before an int $0x80 Linux SYS_EXIT?

I know that its getting 0 into ebx but why? I'm so sorry if it looks like a no-brainer question to you, its my first week of learning assembly and a few months of programming.
I haven't included everything below because it is a quite long, lmk if its necessary
The assembly is from the book "Programming From Ground Up Chapter 6"
summary of assembly:
Opens an input and output file, reads records from the input, increments the age, writes the new record to the output file
SYS_EXIT is 1
LINUX_SYSCALL is 0x80
loop_begin:
pushl ST_INPUT_DESCRIPTOR(%ebp)
pushl $record_buffer
call read_record
addl $8, %esp
# Returns the number of bytes read. If it isn’t the same number we requested, then it’s either an end-of-file, or an error, so we’re quitting
cmpl $RECORD_SIZE, %eax
jne loop_end
#Increment the age
incl record_buffer + RECORD_AGE
#Write the record out
pushl ST_OUTPUT_DESCRIPTOR(%ebp)
pushl $record_buffer
call write_record
addl $8, %esp
jmp loop_begin
loop_end:
movl $SYS_EXIT, %eax
movl $0, %ebx <------------------------ THE INSTRUCTION'S PURPOSE THAT IM ASKING FOR
int $LINUX_SYSCALL
This is the equivalent of _exit(0); in C; except that the Linux kernel uses different calling conventions (parameters passed in registers and not on the stack).
The movl $0, %ebx is loading the 2nd parameter (0) into the right register for the kernel's calling convention. The first parameter is the function number (SYS_EXIT).

Trying to store two numbers using scanf , but program crashes

Given the following code :
.section .rodata
input_format1: .string "%d%d"
output_format1: .string "Yes. %d is a power of %d\n"
output_format2: .string "No. %d is not a power of %d\n"
.section .text
.globl main
.type main, #function
main:
pushl %ebp
movl %esp, %ebp
addl $-8 ,%esp # moving down the stack
pushl %esp
pushl 4(%esp)
pushl $input_format1
call scanf # call scanf to get a number from the user
addl $12,%esp
movl (%esp),%ebx # store the actual number
movl 4(%esp),%ecx
.loop:
#return from printf:
movl %ebp,%esp
popl %ebp
ret
After the program reaches scanf and I press the 1st number ,it crashes.What am I doing wrong ?
Thanks
Ron
The problem is in:
pushl 4(%esp)
That pushes the value in the stack, not the address of such variable.
Compare that with the previous, correct, instruction pushl %esp. This one does push an address.
What you need is pushl %esp+4, but that cannot be done in just one instruction, AFAIK. Instead do something like:
lea 4(%esp), %eax
push %eax
UPDATE:
Your other problem is because each time you do a push %esp gets decremented, so calculating the right address for your local variables is messy. That's one reason to have a stack frame, and you have one! So use %ebp to refer to your local variables, but with a negative offset:
pushl %ebp
movl %esp, %ebp
addl $-8 ,%esp # moving down the stack
lea -4(%ebp), %eax
pushl %eax
lea -8(%ebp), %eax
pushl %eax
pushl $input_format1
call scanf # call scanf to get a number from the user
addl $12,%esp
movl -8(%ebp),%ebx # store the actual number
movl -4(%ebp),%ecx

Printing Range Of ASCII Characters From Registers in x86 Assembly

I'm trying to print a range of ascii characters with this assembly program.
I'm trying to do it using only the registers, but haven't been having much luck. Everything looks fine to me, but I'm a novice at assembly programming and might have missed something obvious. Any insight will be appreciated. Thanks :)
emphasized text
.text
.global _start
_start:
movl $1, %edx
movl $65, %ebx
start_loop:
addl $1, %ebx
movl $0x04, %eax
int $0x80
cmpl $126, %ebx
jle start_loop
jmp start_loop
exit
movl $0, %ebx
movl $1, %eax
int $0x80
You are invoking the sys_write system call. sys_write() takes three arguments, file descriptor of the output device(it should be 1 for stdout),address of the buffer where you stored the value to be printed, and the size of the data to be printed. So you have to store file descriptor in %ebx, and store address of the buffer in %ecx and size of the data in %edx. To store the file descriptor you can use the following instruction.
movl $1, %ebx // store 1 (stdout) in ebx)
To store the size of the data you can use:
movl $1, %edx // size is 1 byte
Now, you have to store the address of the buffer, you need to put your data in the memory some where and need to store the address of the memory in %ecx. Assume that you want store the data in the stack it self, then you can do like this:
subl $4, %esp // get 4 bytes of memory in the stack
movl $65, (%esp) // store data in the memory where esp points to
movl %esp, %ecx // store address of the data in the ecx
Now you can issue the int 0x80.
movl $04, %eax // store syscall number in eax
int $0x80 // issue the trap interrupt
As a whole you can write the following code:
movl $1, %ebx
subl $0x4, %esp
movl $64, (%esp)
start_loop:
movl (%esp), %eax
addl $1, %eax
movl %eax, (%esp)
movl %esp, %ecx
movl $1, %edx
movl $0x04, %eax
int $0x80
movl (%esp), %eax
cmpl $126, %eax
jle start_loop
addl $0x4, %esp
See Linux System Calls Part2 at http://www.rulingminds.com/syscallspart2 to know more about registers and system calls usage.
"Thank you very much for the informative answer, but is there a way to store and retrieve the value to be printed in a register without pointing to it?" -- this should probably have been edited into the question.
If you insist on using only syscalls (int $0x80) to interface with the system then the answer is no. You have to somehow pass a buffer to write and rullingminds answer applies.
Using the libc putchar(3) it's straight forward. I use %ebx to keep the ascii code as this register is on linux preserved between function calls. Simply assemble using gcc filename.S (remembering to use -m32 if you are on x86_64).
.text
.extern putchar
.global main
main:
# make room for argument to putchar on the stack
sub $4, %esp
# initialize ebx with first value to print
mov $'A', %ebx
1:
# give character to print as argument
mov %ebx, (%esp)
call putchar
# move to next character
inc %ebx
# are we done?
cmp $'~', %ebx
jle 1b
# print newline
movl $10, (%esp)
call putchar
# adjust stack back to normal
add $4, %esp
# return 0 from main
mov $0, %eax
ret

Bogus Results from Simple Assembly Program on FreeBSD System

I've been having problems getting even the simplest of assembly programs that I write on Linux to run on my FreeBSD machine. Here's the offending code (I'm trying to keep this as simple as possible):
#counts to sixty
.section .data
.section .text
.global _start
_start:
movl $1, %ecx #move $1 into ecx
movl $1, %eax
start_loop:
addl %ecx, %eax #add ecx to eax
cmpl $60, %eax #compare $60 and eax...
je end_loop #if eax = 60 go to end_loop
cmpl $60, %eax #
jle start_loop #jump if eax is < $60...
jmp start_loop #...to start_loop
end_loop:
movl %eax, %ebx #move the value of eax into ebx because ebx holds
#the return value
movb $1, %al #Move $1 into eax (int 1 is the value for the
#exit() syscall
int $0x80
The Linux machine returns the expected resulted which is sixty, whereas the FreeBSD machine consistently returns 164 for the return code. Does anybody know why this is? If so, can you please explain to me what is happening? Also, I should mention that they are both indeed running x86 CPUs. Thanks in advance :)
Refer to the FreeBSD Developer's handbook, and you need to do:
push %eax
mov $1, %eax
push %eax
int $0x80
because:
only the system call vector is passed via register %eax, all arguments are on the stack
the FreeBSD default syscall expects an additional word on the stack, which would be a dummy for inlined uses of int $0x80 but a return address where you do a syscall via a call kernel_entry trampoline (that then can do int $0x80; ret).
If you want to use the Linux convention (some syscall args in regs, called "Alternative Calling convention" in the manual), you have to brand the executable so that the system knows you're using Linux-style syscalls.

creating a substring on Linux IA-32 assembler (gas)

I wanna create a substring (ministring) of 3 asciz chars out of my original (thestring). The thing ain't printing when being run so I don't know what the hell I'm I doing. Why it ain't printing? Am I creating the ministring correctly?
.section .data
thestring: .asciz "111010101"
ministring: .asciz ""
formatd: .asciz "%d"
formats: .asciz "%s"
formatc: .asciz "%c"
.section .text
.globl _start
_start:
xorl %ecx, %ecx
ciclo:movb thestring(%ecx,1), %al
movzbl %al, %eax
movl %eax, ministring(%ecx,1)
incl %ecx
cmpl $3, %ecx
jl ciclo
movl thestring, %eax
pushl %eax
pushl $formats
call printf
addl $4, %esp
movl $1, %eax
movl $0, %ebx
int $0x80
You haven't reserved enough memory space to contain the null-terminated ministring which you're creating ... therefore, when you write to this memory, you're overwriting the value of formatd and formats (and so you're eventually passing something other than "%s" to printf).
Instead of your definition of the ministring memory location, try using the following :
ministring: .asciz " "
Also, instead of this:
movl %eax, ministring(%ecx,1)
I don't understand why you aren't using this instead:
movb %al, ministring(%ecx,1)
Also, if you want to print the ministring, then instead of this:
movl thestring, %eax
Do this:
movl ministring, %eax
Also instead of this:
addl $4, %esp
Why not this:
addl $8, %esp
ALso I suggest that you use a debugger to:
Step through the code
Watch the values contained in registers and in memory as you step through
Know the location of any segmentation fault

Resources