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

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.

Related

Problems with writing an x86 Assembly program that reverses two words separated by a space

I'm trying to write a program that takes a string input of two words, then reverses the order of the words and prints them. Right now I'm struggling with a few problems because the teacher didn't teach us how to write x86 assembly very well.
Currently I'm trying to figure out how to:
Find the start of the array again, as I believe the current program messes with the stack, and printing ♣ at 8(%esp,%ebx) when %ebx = 0
How to store %ebx when the index hits the space, preferably into the register of %ecx, though I do not know how to prevent _printf from messing with %ecx in the current set up
Lastly, whenever I input two words where the first word is smaller than 3 letters it doesn't output the 2nd word.
Right now, this is the output of my program (when the input is "Hello World")
Enter a string:
Hello World (input)
Your string is:
Hello World
Index of Space is = 6
World♣ <--- Supposed to be World Hello, in this case just testing to make sure I can find the 1st element of %eax
The registers I am currently using are %eax for the string array, and %ebx for the index of %eax. I would like to use %ecx, or any other register to store %ebx value when %ebx hits the space character.
Here is my x86 Assembly code so far:
LC0:
.ascii "Enter a string: \0"
LC1:
.ascii "%[^\n]\0"
LC2:
.ascii "Your string is:\12\0"
LC3:
.ascii "\12Index of Space is = %d\12\0"
LC4:
.ascii "%c\0" # print out the character
LC6:
.ascii "Yeehaw!\0" # test message
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
pushl %ebp
movl %esp, %ebp
pushl %ebx
subl $112, %esp
movl $LC0, (%esp)
call _puts # similar to _printf function
leal 8(%esp), %eax
movl %eax, 4(%esp)
movl $LC1, (%esp)
call _scanf # get string
movl $LC2, (%esp)
call _printf # printout the output text of LC2
###### A[i] ###### ebx is the index
movl $0, %ebx #index of array i=0
movl $0, %ecx # Where I want to store space index
jmp .L2
.L1: #TEXT PORTION
movsbl %al, %eax # eax =FFFFFFXX XX means for each character print out the input character
incl %ebx # next index of array
movl %eax, 4(%esp) # print out from the first element of the array
movl $LC4, (%esp)
call _printf
.L2: #TEXT PORTION
movzbl 8(%esp,%ebx), %eax # the value of esp+8+0 strating address of the array to eax
cmpb $0x20, %al # compare eax to see if it is a space
jne .EndOfLine
movl %ebx, 8(%esp) # Save space index
.EndOfLine:
testb %al, %al # if eax is not equal to zero jump to L3, if is zero menas end of the string
jne .L1
movl 8(%esp), %ebx # Take space index back
incl %ebx
#States space index
movl %ebx, 4(%esp) # print out from the first element of the array
movl $LC3, (%esp)
call _printf
jmp .T2
.T1: #TEXT PORTION
movsbl %al, %eax # eax =FFFFFFXX XX means for each character print out the input character
incl %ebx # next index of array
movl %eax, 4(%esp) # print out from the first element of the array
movl $LC4, (%esp)
call _printf
.T2: #TEXT PORTION
movzbl 8(%esp,%ebx), %eax # the value of esp+8+0 strating address of the array to eax
testb %al, %al # if eax is not equal to zero jump to L3, if is zero menas end of the string
jne .T1
.Test:
#Test to find initial array value, currently prints ♣ at 8(%esp,$0)
movl $0, %ebx
movzbl 8(%esp,%ebx), %eax
movsbl %al, %eax
movl %eax, 4(%esp)
movl $LC4, (%esp)
call _printf
.Done:
movl $0, %eax
addl $112, %esp
leave
ret
Any help would be appreciated, and if explain why I need to do certain things since my teacher wasn't the best at explaining topics like the stack and such.
UPDATE: 8(%esp,%ebx) when ebx is 0 properly locates the initial letter, and using $116(%esp) as a local variable to store %ebx.

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

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.

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