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
Related
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.
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.
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
simple upper-casifier loop infinitely
what's wrong with my code?
any advice?
my programming environment is linux, emacs, assembly, at&t syntax
.section .data
.section .bss
.lcomm buffer,1
.section .text
.global _start
_start:
movl %esp,%ebp
subl $8,%esp
#8(%ebp) is 2nd arg == input
#12(%ebp) is 3rd arg == output
#open,read,open,write,close
movl $5,%eax
movl 8(%ebp),%ebx
movl $0,%ecx
movl $0666,%edx
int $0x80
#%eax contains input's fd
#movl to first local var
movl %eax,-4(%ebp)
movl $5,%eax
movl 12(%ebp),%ebx
movl $03101,%ecx
movl $0666,%edx
int $0x80
#eax contains output's fd
#movl to second local var
movl %eax,-8(%ebp)
loop:
#read 1 byte from file 1st byte of data
movl $3,%eax
movl -4(%ebp),%ebx
movl $buffer,%ecx
movl $1,%edx
int $0x80
#buffer contains 1 byte of file
cmpb $0,buffer
je program_exit
pushl buffer
call convert #will return converted to %al
addl $4,%esp
movb %al,buffer
#write 1 byte from buffer to file
movl $1,%edx
movl $buffer,%ecx
movl -8(%ebp),%ebx
movl $4,%eax
int $0x80
jmp loop
program_exit:
movl buffer,%ebx
movl $1,%eax
int $0x80
.type convert,#function
convert:
pushl %ebp
movl %esp,%ebp
movb 8(%ebp),%al #1 byte data in the buffer
cmpb $'a',%al
jl convert_end
cmpb $'z',%al
jg convert_end
addb $32,%al #convert to upper
convert_end:
movl %ebp,%esp
popl %ebp
ret
Note that read(2) signals an end-of-file condition by returning 0. You're trying to find the end of the file by looking for an ascii NUL, which is very rare on Unix-derived systems. (If you want an easy way to make a terabyte-sized file, dd if=/dev/zero of=/tmp/huge bs=1048576 seek=1048576 count=1. The whole thing will be filled with ascii NUL characters. (Or the integer 0, however you want to interpret it.)
You need to modify your code to find the end of file by comparing the return value of the read(2) system call, not by looking at the data you receive into your buffer.
I found a pdf file called: ProgrammingGroundUp-1-0-booksize.pdf, and one of the projects is to make an assembly program that takes in files and converts them to uppercase, `
.section .data
#######CONSTANTS########
#system call numbers
.equ SYS_OPEN, 5
.equ SYS_WRITE, 4
.equ SYS_READ, 3
.equ SYS_CLOSE, 6
.equ SYS_EXIT, 1
#options for open (look at
#/usr/include/asm/fcntl.h for
#various values. You can combine them
#by adding them or ORing them)
#This is discussed at greater length
#in "Counting Like a Computer"
.equ O_RDONLY, 0
.equ O_CREAT_WRONLY_TRUNC, 03101
#standard file descriptors
.equ STDIN, 0
.equ STDOUT, 1
.equ STDERR, 2
#system call interrupt
.equ LINUX_SYSCALL, 0x80
.equ END_OF_FILE, 0
#This is the return value
#of read which means we’ve
#hit the end of the file
.equ NUMBER_ARGUMENTS, 2
.section .bss
.equ BUFFER_SIZE, 500
.lcomm BUFFER_DATA, BUFFER_SIZE
.section .text
#STACK POSITIONS
.equ ST_SIZE_RESERVE, 8
.equ ST_FD_IN, -4
.equ ST_FD_OUT, -8
.equ ST_ARGC, 0
#Number of arguments
.equ ST_ARGV_0, 4
#Name of program
.equ ST_ARGV_1, 8
#Input file name
.equ ST_ARGV_2, 12
#Output file name
.globl _start
_start:
###INITIALIZE PROGRAM###
#save the stack pointer
movl %esp, %ebp
#Allocate space for our file descriptors
#on the stack
subl $ST_SIZE_RESERVE, %esp
open_files:
open_fd_in:
###OPEN INPUT FILE###
#open syscall
movl $SYS_OPEN, %eax
#input filename into %ebx
movl ST_ARGV_1(%ebp), %ebx
#read-only flag
movl $O_RDONLY, %ecx
#this doesn’t really matter for reading
movl $0666, %edx
#call Linux
int $LINUX_SYSCALL
store_fd_in:
#save the given file descriptor
movl %eax, ST_FD_IN(%ebp)
open_fd_out:
###OPEN OUTPUT FILE###
#open the file
movl $SYS_OPEN, %eax
#output filename into %ebx
movl ST_ARGV_2(%ebp), %ebx
#flags for writing to the file
movl $O_CREAT_WRONLY_TRUNC, %ecx
#mode for new file (if it’s created)
movl $0666, %edx
#call Linux
int
$LINUX_SYSCALL
store_fd_out:
#store the file descriptor here
movl %eax, ST_FD_OUT(%ebp)
###BEGIN MAIN LOOP###
read_loop_begin:
###READ IN A BLOCK FROM THE INPUT FILE###
movl $SYS_READ, %eax
#get the input file descriptor
movl ST_FD_IN(%ebp), %ebx
#the location to read into
movl $BUFFER_DATA, %ecx
#the size of the buffer
movl $BUFFER_SIZE, %edx
#Size of buffer read is returned in %eax
int
$LINUX_SYSCALL
###EXIT IF WE’VE REACHED THE END###
#check for end of file marker
cmpl $END_OF_FILE, %eax
#if found or on error, go to the end
jle end_loop
continue_read_loop:
###CONVERT THE BLOCK TO UPPER CASE###
pushl $BUFFER_DATA
#location of buffer
pushl %eax
#size of the buffer
call convert_to_upper
popl %eax
#get the size back
addl $4, %esp
#restore %esp
###WRITE THE BLOCK OUT TO THE OUTPUT FILE###
#size of the buffer
movl %eax, %edx
movl $SYS_WRITE, %eax
#file to use
movl ST_FD_OUT(%ebp), %ebx
#location of the buffer
movl $BUFFER_DATA, %ecx
int $LINUX_SYSCALL
###CONTINUE THE LOOP###
jmp read_loop_begin
end_loop:
###CLOSE THE FILES###
#NOTE - we don’t need to do error checking
movl $SYS_CLOSE, %eax
movl ST_FD_OUT(%ebp), %ebx
int $LINUX_SYSCALL
movl ST_FD_IN(%ebp), %ebx
movl $SYS_CLOSE, %eax
int $LINUX_SYSCALL
###EXIT###
movl $SYS_EXIT, %eax
movl $0, %ebx
int $LINUX_SYSCALL
###CONSTANTS##
#The lower boundary of our search
.equ LOWERCASE_A, ’a’
#The upper boundary of our search
.equ LOWERCASE_Z, ’z’
#Conversion between upper and lower case
.equ UPPER_CONVERSION, ’A’ - ’a’
###STACK STUFF###
.equ ST_BUFFER_LEN, 8 #Length of buffer
.equ ST_BUFFER, 12
#actual buffer
convert_to_upper:
pushl %ebp
movl %esp, %ebp
###SET UP VARIABLES###
movl ST_BUFFER(%ebp), %eax
movl ST_BUFFER_LEN(%ebp), %ebx
movl $0, %edi
#if a buffer with zero length was given
#to us, just leave
cmpl $0, %ebx
je end_convert_loop
convert_loop:
#get the current byte
movb (%eax,%edi,1), %cl
#go to the next byte unless it is between
#’a’ and ’z’
cmpb $LOWERCASE_A, %cl
jl next_byte
cmpb $LOWERCASE_Z, %cl
jg next_byte
#otherwise convert the byte to uppercase
addb $UPPER_CONVERSION, %cl
#and store it back
movb %cl, (%eax,%edi,1)
next_byte:
incl %edi
#next byte
cmpl %edi, %ebx
#continue unless
#we’ve reached the
#end
jne convert_loop
end_convert_loop:
#no return value, just leave
movl %ebp, %esp
popl %ebp
ret
`
the assembler is called "as", and the code is on page 87 of the file, you can easily get if you look it up on google, also the code doesn't copy and paste correctly for some reason, so you might sometimes see things like:
jmp
to_another_point
I tried to get rid of as many of those as I could, but there still might be some, and some of the comments were probably lost in the process, so I would suggest opening the original pdf file.
I am running Ubuntu linux version 10.04.1, I am using as version 2.20.1, and the problem is that it creates the file, but the file is always empty.
The source for this book is available, and if you browse the appropriate part of the CVS repository you can find .s source files for the various examples.
This code is toupper.s - you can just download the most recent revision instead of messing around with copy-and-paste.
I've just tried that (on a Debian system; I don't have anything running Ubuntu 10.04 to hand), assembling and linking exactly as described in the book, and it worked fine.
I think you can subtract 32 from the value of the letters to get it in Upper case, since they have a difference in value of 32. Like this:
make_cap: # function fore making capital letters
sub $32, al # subtract 32 from the value of the character
jmp other_function
pop
ret