Call for a function doesn't work - linux

Given the following code :
.globl main
.type main, #function
input: .string "%d"
main:
pushl %ebp # save the old frame pointer
movl %esp,%ebp # create the new frame pointer
movl $0,%eax
addl $-4 ,%esp # moving down the stack
pushl %esp # push the address of esp to the stack in order to store the number given by the user
pushl $input # push to the stack the format of the input
call scanf # call scanf to get a number from the user
addl $8,%esp # clear the stack
movl (%esp),%eax # get the selection from the user
subl $50,%eax
jmp *.switching(,%eax,4)
.section .rodata
.align 4
.switching:
.long .L1
.long .L2
.long .L3
.long .L4
.text
.L1:
call case1
jmp .quitTheProgram
.L2:
call case2
jmp .quitTheProgram
.L3:
call case
jmp .quitTheProgram
.L4:
call case4
jmp .quitTheProgram
case1:
pushl %ebp # save the old frame pointer
movl %esp,%ebp # create the new frame pointer
#
# code of case1
#
movl %ebp,%esp # restore the old ebp
popl %ebp # restore the old stack pointer and release all used memory
ret # return to caller function (OS)
The user presses numbers between 50-54. The problem is after pressing (for example) 50
I jump to case1 , but not to the code itself , but straight to the ret line , and then the code stops and exit case1 (as for the rest of the cases) .
What might be the problem ?
Regards,Ron

The problem is after pressing (for example) 50 I jump to case1 , but not to the code itself , but straight to the ret line
I just built your code on Linux, stepped through it in GDB, and did not observe that behavior.
It is somewhat likely that you are mis-interpreting what you actually observed.

Related

Convert a string of digits to an integer by using a subroutine

Assembly language program to read in a (three-or-more-digit) positive integer as a string and convert the string to the actual value of the integer.
Specifically, create a subroutine to read in a number. Treat this as a string, though it will be composed of digits. Also, create a subroutine to convert a string of digits to an integer.
Do not have to test for input where someone thought i8xc was an integer.
I am doing it like this. Please help.
.section .data
String:
.asciz "1234"
Intg:
.long 0
.section .text
.global _start
_start:
movl $1, %edi
movl $String, %ecx
character_push_loop:
cmpb $0, (%ecx)
je conversion_loop
movzx (%ecx), %eax # move byte from (%ecx) to eax
pushl %eax # Push the byte on the stack
incl %ecx # move to next byte
jmp character_push_loop # loop back
conversion_loop:
popl %eax # pop off a character from the stack
subl $48, %eax # convert to integer
imul %edi, %eax # eax = eax*edi
addl %eax, Intg
imul $10, %edi
decl %ecx
cmpl $String, %ecx # check when it get's to the front %ecx == $String
je end # When done jump to end
jmp conversion_loop
end:
pushl Intg
addl $8, %esp # clean up the stack
movl $0, %eax # return zero from program
ret
Also, I am unable to get the output. I am getting a Segmentation Fault. I am not able to find out what is the error in my code.
Proper interaction with operating system is missing.
In the end: you pushed the result but the following addl $8, %esp invalidates the pushed value and the final ret incorrectly leads the instruction flow to whatever garbage was in the memory pointed by SS:ESP+4 at the program entry.
When you increase the stack pointer, you cannot rely that data below ESP will survive.
Your program does not interact with its user, if you want it to print something, use system function to write.
print_String:
mov $4,eax ; System function "sys_write".
mov $1,ebx ; Handle of the standard output (console).
mov $String,ecx ; Pointer to the text string.
mov $4,edx ; Number of bytes to print.
int 0x80 ; Invoke kernel function.
end:mov $1,eax ; System function "sys_exit".
mov (Intg),ebx ; Let your program terminate gracefully with errorlevel Intg.
int 0x80 ; Invoke kernel function.

asm X86 - segmentation fault? [duplicate]

This question already has an answer here:
x64: Why does this piece of code give me "Address boundary error"
(1 answer)
Closed 5 years ago.
Introduction
I'm following "ProgrammingGroundUp" book. and I've followed the example of creating a function to raise the power of two numbers and adding them. "2^3 + 5^2". However when I go to compile the code, and then run the program. I receive a segmentation fault.
From my understanding a segmentation fault occurs when a program attempts to do an illegal read or write from a memory location. I think it could be occurring inside the function itself, however confused of where the segmentation fault has occurred.
Source Code - power.s
#purpose illustrate how functions work. Program will compute 2^3 + 5^2
#using registers so nothing in data section
.section .data
.section .text
.globl _start
_start:
pushl $3 #push 2nd arg on stack
pushl $2 #push 1st arg on stack
call power
addl 8,%esp #move stack pointer back
pushl %eax #push result to top of stack
pushl $2 #push 2nd arg on stack
pushl $5 #push 1st arg on stack
call power
addl 8,%esp #move stack pointer back
popl %ebx #put function1 result into ebx reg
addl %eax , %ebx #add return result of function2 + function1 result
movl $1 , %eax #exit system call
int $0x80
#PURPOSE: power function
#REGISTERS: %ebx - holds base number ; %ecx - holds power; -4(%ebp) -holds current result ;%eax temp storage
.type power,#function
power:
pushl %ebp #save state of base pointer
movl %esp,%ebp #make stack pointer the base pointer
subl $4,%esp #room for local storage
movl 8(%ebp),%ebx #1st arg initialized,
movl 12(%ebp),%ecx #2nd arg initialized,
movl %ebx , -4(%ebp) #store current result
power_loop_start:
cmpl $1,%ecx #if ^1 then jump to end_power & exit
je end_power
movl -4(%ebp),%eax #store current result
imull %ebx,%eax #multiply
movl %eax,-4(%ebp) #store result
decl %ecx #decrement ecx
jmp power_loop_start #loop
end_power: #return
movl -4(%ebp) , %eax #move result in eax for return
movl %ebp , %esp #reset the stack pointer
popl %ebp #reset base pointer to original position
ret #return
Compiling
as --32 power.s -o power.o
ld -m elf_i386 power.o -o power
./power
Segmentation fault
Summary
Segmentation fault occurring in code, Not sure where is exactly, very new to assembly, tried to explain as best I can. BTW used the "--32" as the code is 32bit and I'm on a 64bit machine.
*Also if my question doesn't meet stack overflow standards please let me know so I can improve.
Thanks to #Michael Petch for spotting the syntax error. In lines such as "addl 8,%esp" i did not put the dollar sign, which signifies a value and not a memory address as the instruction is immediate addressing. However i miseed the dollar sign which makes it into a memory address. Thanks for helping.

mmap and string operations in assembler

I am trying to code something that allocates some memory for a string and fills that memory with random characters.
Now I decided to go the way of mmap-syscalls, without using malloc functions.
Here is my code:
.code32
.data
random: .ascii "/dev/random\0"
.section .data
c: .ascii "t" #just a test static character, for test
n: .ascii "\n" #end of string
.text
.global _start
_start:
pushl $0 # offset of 0
pushl $-1 # the file handle of the open file
pushl $33 # MAP_SHARED flag set to write changed data back to file
pushl $3 # PROT_READ and PROT_WRITE permissions
pushl $42
pushl $0 # Allow the system to select the location in memory to start
movl %esp,%ebx # copy the parameters location to EBX
movl $90,%eax # set the system call value
int $0x80
movl %eax,%edi #the adress of allocated memory is stored in edi
pushl %eax #save the adress on stack
movl $42, %ecx #now i want to generate 42 random symbols and print them
loop:
dec %ecx
pushl %ecx #generate a random number, using the kernel Entropy Collector
movl $5,%eax # sys_open
movl $random,%ebx # Filename string
movl $0,%ecx # O_RDONLY flag
int $0x80
# Read one random number
movl %eax,%ebx # The result of sys_open
movl $3,%eax # sys_read
movl (%esp),%ecx # The stack is our buffer
movl $1,%edx #
int $0x80 #random number on stack
popl %eax #eax represents the random number
movl $100,%ebx
divl %ebx #modulo 223
leal 34(%edx),%eax
stosb #load a random char into allocated memory
popl %ecx
cmpl $0,%ecx
jne loop
movl $4,%eax #syscall write
movl $1,%ebx
movl $43,%edx
popl %ecx #pop the saved adress of string
int $0x80
movl $1,%eax #exit
int $0x80
`
which causes a segfault in MOVSB - operation.
So I am not sure about a couple of things:
The way I just push integers between 33 and 255 to ESI before the MOVSB, hoping that the integer will be recognized as an ascii sign, for which it stands.
The way I allocate memory
Also not quite sure about the correctness of the LEAL - operation,
which aims to just move through the allocated (42??) bytes of memory each time jumping to a new byte. Although this one can not cause the segfault as it comes after the error-causing MOVSB.
##### EDIT: Stack faults fixed by setting correct flags in mmap-call and changing movsb to stosb

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

simple adder isn't working

I made simple arguments adder with assembly but it isn't working
it always return 0
.section .data
.section .text
.global _start
_start:
call adder
movl %eax,%ebx
movl $1,%eax
int $0x80
adder:
pushl %ebp
movl %esp,%ebp
movl $0,%eax #eax = return
movl $1,%ebx #ebx = index
movl 8(%ebp),%ecx #number of args
loop:
cmpl %ebx,%ecx
jg exit
addl 8(%ebp,%ebx,4),%eax
incl %ebx
jmp loop
exit:
movl %ebp,%esp
popl %ebp
ret
There are a few problems with this code, but you're on the right track.
1. Loop condition
You are using this to quit the loop when ebx >= ecx:
cmpl %ebx,%ecx
jg exit
The syntax is rather confusing, but this actually means "exit if ecx is greater than ebx". Changing it to jng exit fixes this problem.
2. Arguments on stack
You are referring to arguments with 8(%ebp,%ebx,4), but the arguments actually start at 12(%ebp). You are right in that you should start with index 1, because the argument with index 0 is merely the name of the program.
3. Arguments are always strings
The arguments on the stack are only pointers to strings. movl 12(%ebp),%eax will not put a number from the command line in eax. It will only put a memory address in eax, which points to a series of characters that make up the first argument.
To get the number represented by the string "123" you need to parse it with a function such as atoi. atoi will then return 123 in eax.
Here's what the code looks like once these things are fixed. I put a comment next to each changed line.
.section .data
.section .text
.global _start
_start:
call adder
movl %eax,%ebx
movl $1,%eax
int $0x80
adder:
pushl %ebp
movl %esp,%ebp
movl $0,%eax #eax = return
movl $1,%ebx #ebx = index
movl 8(%ebp),%ecx #number of args
loop:
cmpl %ebx,%ecx
jng exit # quit if ecx is not greater than ebx
pushl %eax # save registers on stack
pushl %ecx # because they will be destroyed soon
pushl 12(%ebp,%ebx,4) # push next argument pointer on stack
call atoi # invoke atoi, this destroys registers eax,ecx,edx
add $4,%esp # restore stack pointer
mov %eax,%edx # atoi returns the value in eax, save that to edx
popl %ecx # restore ecx from stack
popl %eax # restore eax from stack
addl %edx,%eax # add parsed number to accumulator
incl %ebx
jmp loop
exit:
movl %ebp,%esp
popl %ebp
ret
And the program seems to work now:
$ gcc -nostartfiles test.S -m32 && ./a.out 1 2 3 4 5 ; echo $?
15
The program returns the result in its exit value, which means it can not count higher than 255 :)
It would probably be better to let the program print the result to stdout, using printf.

Resources