How to read and write a byte from and to stdin/stdout using Syscall in x86 with NASM assembler? - io

I am trying to read a string from stdin and print it back out using x86, NASM, and Syscalls. Reading in a byte will be a function, and writing out a byte will be a function. I am reading the string from stdin and putting each char into an array. Here is my initial idea:
;read_writer.asm
section .data
arr times 100 db 0 ; array of 100 elements initialzed to 0
ptr dd 0
section .text
global _start
_start:
push ebp ; setup stack
mov ebp, esp ; setup stack
push, 0x10 ; allocate space for potential local variables
call readin: ;call read in func
push eax ;return char from readin will be in eax, push it for writeout
call writeout:
leave
mov eax, 1 ;exit
mov ebx, 0
int 0x80
readin:
push ebp
mov ebp, esp ; setup stack
mov eax, 3 ;read
mov ebx, 1 ;stdin
; i feel like i am missing code here bit not sure what
leave ;reset stack
ret ;return eax
writeout:
push ebp
mov ebp, esp ; setup stack
push eax ;push eax since it was pushed earlier
mov eax, 4 ;write
mov ebx, 1 ;stdout
; i feel like i am missing code here bit not sure what
leave ;reset stack
ret ;return eax
Sample input:
Hello World
Sample output:
Hello World
The functions should be used with cdecl, which I dont think I am doing correctly. I also realised I am not putting the chars into arr.

For starters, you're missing the int 0x80 in both readin and writeout.
And, as you can see here, both sys_read and sys_write expect a (const) char* in ecx. That address should point to the buffer where the bytes to write are stored / the read bytes should be stored.The value of edx should be set to the number of bytes to read / write.
So in the readin example you want something like:
mov eax, 3 ;read
mov ebx, 0 ;stdin. NOTE: stdin is 0, not 1
sub esp,4 ; Allocate some space on the stack
mov ecx,esp ; Read characters to the stack
mov edx,1
int 0x80
movzx eax,byte [esp] ; Place the character in eax, which is used for function return values
add esp,4
And similarly for writeout.

Related

To display characters in reverse order using nasm [infinite loop running]

THE PROGRAM IS USED TO ACCEPT CHARACTERS AND DISPLAY THEM IN REVERSE ORDER
The code is included here:
section .bss
num resb 1
section .text
global _start
_start:
call inputkey
call outputkey
;Output the number entered
mov eax, 1
mov ebx, 0
int 80h
inputkey:
;Read and store the user input
mov eax, 3
mov ebx, 2
mov ecx, num
mov edx, 1
int 80h
cmp ecx, 1Ch
je .sub2
push ecx
jmp inputkey
.sub2:
push ecx
ret
outputkey:
pop ecx
;Output the message
mov eax, 4
mov ebx, 1
;mov ecx, num
mov edx, 1
int 80h
cmp ecx, 1Ch
je .sub1
jmp outputkey
.sub1:
ret
The code to compile and run the program
logic.asm
is given here:
nasm -f elf logic.asm
ld -m elf_i386 -s -o logic logic.o
./logic
There are a few problems with the code. Firstly, for the sys_read syscall (eax = 3) you supplied 2 as the file descriptor, however 2 refers to stderr, but in this case you'd want stdin, which is 0 (I like to remember it as the non-zero numbers 1 and 2 being the output).
Next, an important thing to realize about the ret instruction is that it pops the value off the top of the stack and returns to it (treating it as an address). Meaning that even if you got to the .sub2 label, you'd likely get a segfault. With this in mind, the stack also tends to not be permanent storage, as in it is not preserved throughout procedures, so I'd recommend just making your buffer larger to e.g. 256 bytes and increment a value to point to an index in the buffer. (Using a fixed-size buffer will keep you from getting into the complications of memory allocation early, though if you want to go down that route you could do an external malloc call or just an mmap syscall.)
To demonstrate what I mean by an index into the reserved buffer:
section .bss
buf resb 256
; ...
inputkey:
xor esi, esi ; clear esi register, we'll use it as the index
mov eax, 3
mov ebx, 0 ; stdin file descriptor
mov edx, 1 ; read one byte
.l1: ; loop can start here instead of earlier, since the values eax, ebx and edx remain unchanged
lea ecx, [buf+esi] ; load the address of buf + esi
int 80h
cmp [buf+esi], 0x0a ; check for a \n character, meaning the user hit enter
je .e1
inc esi
jmp .l1
.e1:
ret
In this case, we also get to preserve esi up until the output, meaning that to reverse the input, we just print in descending order.
outputkey:
mov eax, 4
mov ebx, 1 ; stdout
mov edx, 1
.l2:
lea ecx, [buf+esi]
int 80h
test esi, esi ; if esi is zero it will set the ZF flag
jz .e2:
jmp .l2
.e2:
ret
Note: I haven't tested this code, so if there are any issues with it let me know.

Print ARGC in NASM without printf

Any good NASM/Intel Assembly programmers out there? If so, I have a question for you!
Every tutorial I can find online, shows the usage of "printf" for printing the actual value of ARGC to the screen (fd:/dev/stdout). Is it not possible to simply print it with sys_write() for example:
SEGMENT .data ; nothing here
SEGMENT .text ; sauce
global _start
_start:
pop ECX ; get ARGC value
mov EAX, 4 ; sys_write()
mov EBX, 1 ; /dev/stdout
mov EDX, 1 ; a single byte
int 0x80
mov EAX, 1 ; sys_exit()
mov EBX, 0 ; return 0
int 0x80
SEGMENT .bss ; nothing here
When I run this, I get no output at all. I have tried copying ESP into EBP and tried using byte[EBP+4], (i was told the brackets de-reference the memory address).
I can confirm that the value when compared to a constant, works. For instance,
this code works:
pop ebp ; put the first argument on the stack
mov ebp, esp ; make a copy
cmp byte[ebp+4],0x5 ; does it equal 5?
je _good ; goto _good, &good, good()
jne _bad ; goto _bad, &bad, bad()
When we "pop" the stack, we technically should get the full number of arguments, no? Oh, btw, I compile with:
nasm -f elf test.asm -o test.o
ld -o test test.o
not sure if that is relevant. Let me know if i need to provide more information, or format my code for readability.
At least 2 problems.
You need to pass a pointer to the thing you want to print.
You probably want to convert to text.
Something like this should work:
SEGMENT .text ; sauce
global _start
_start:
mov ecx, esp ; pointer to ARGC on stack
add byte [esp], '0' ; convert to text assuming single digit
mov EAX, 4 ; sys_write()
mov EBX, 1 ; /dev/stdout
mov EDX, 1 ; a single byte
int 0x80
mov EAX, 1 ; sys_exit()
mov EBX, 0 ; return 0
int 0x80
Everyone's comments where very helpful! I am honored that you all pitched in and helped! I have used #Jester's code,
SEGMENT .text ; sauce
global _start
_start:
mov ecx, esp ; pointer to ARGC on stack
add byte [esp], '0' ; convert to text assuming single digit
mov EAX, 4 ; sys_write()
mov EBX, 1 ; /dev/stdout
mov EDX, 1 ; a single byte
int 0x80
mov EAX, 1 ; sys_exit()
mov EBX, 0 ; return 0
int 0x80
Which works perfectly when compiled, linked and loaded. The sys_write() function requires a pointer, such like in the common "Hello World" example, the symbol "msg" is a pointer as seen in the code below.
SECTION .data ; initialized data
msg: db "Hello World!",0xa
SECTION .text ; workflow
global _start
_start:
mov EAX, 4
mov EBX, 1
mov ECX, msg ; a pointer!
So first, we move the stack pointer into the counter register, ECX, with the code,
mov ecx, esp ; ecx now contains a pointer!
and then convert it to a string by adding a '0' char to the value pointed to by ESP (which is ARGC), by de-referencing it with square brackets, as [ESP] like so,
add byte[esp], '0' ; update the value stored at "esp"
Again, thank you all for the great help! <3

Insertion sort not working, 32bit assembly

I'm trying to implement insertion sort in 32bit assembly in linux using NASM and I get a segmentation fault mid-run (not to mention that for some reason 'printf' prints random garbage values, I'm not totally sure why), Here is the
code:
section .rodata
MSG: DB "welcome to sortMe, please sort me",10,0
S1: DB "%d",10,0 ; 10 = '\n' , 0 = '\0'
section .data
array DD 5,1,7,3,4,9,12,8,10,2,6,11 ; unsorted array
len DB 12
section .text
align 16
global main
extern printf
main:
push MSG ; print welcome message
call printf
add esp,4 ; clean the stack
call printArray ;print the unsorted array
;parameters
;push len
;push array
mov eax, len
mov ebx, array
push eax
push ebx
call myInsertionSort
call printArray ; print the sorted one
mov eax, 1 ;exit system call
int 0x80
printArray:
push ebp ;save old frame pointer
mov ebp,esp ;create new frame on stack
pushad ;save registers
mov eax,0
mov ebx,0
mov edi,0
mov esi,0 ;array index
mov bl, byte [len]
add edi,ebx ; edi = array size
print_loop:
cmp esi,edi
je print_end
push dword [array+esi*4]
push S1
call printf
add esp, 8 ;clean the stack
inc esi
jmp print_loop
print_end:
popa ;restore registers
mov esp,ebp ;clean the stack frame
pop ebp ;return to old stack frame
ret
myInsertionSort:
push ebp
mov ebp, esp
push ebx
push esi
push edi
mov ecx, [ebp+12]
movzx ecx, byte [ecx] ;put len in ecx, our loop variable
mov eax, 0
mov ebx, 0
mov esi, [ebp+8] ; the array
loop loop_1
loop_1:
cmp ecx, 0 ; if we're done
je done_1 ; then done with loop
mov edx, ecx
push ecx ; we save len, because loop command decrements ecx
sub edx, ecx
mov ecx, [esi+4*edx] ;;;;;; ecx now array[i] ? how do I access array[i] in a similar manner?
mov ebx, eax
shr ebx, 2 ; number of times for inner loop
loop_2:
cmp ebx, 0 ; we don't use loop to not affect ecx so we use ebx and compare it manually with 0
jl done_2
cmp [esi+ebx], ecx ;we see if array[ebx] os ecx so we can exit the loop
jle done_2
lea edx, [esi+ebx]
push dword [edx] ; pushing our array[ebx]
add edx, 4
pop dword [edx] ; popping the last one
dec ebx ; decrementing the loop iterator
jmp loop_2 ; looping again
done_2:
mov [esi+ebx+1], ecx
inc eax ; incrementing iterator
pop ecx ; len of array to compare now to eax and see if we're done
jmp loop_1
done_1:
pop edi
pop esi
pop ebx
pop ebp ; we pop them in opposite to how we pushed
ret
About the printf thing, I'm positive that I should push the parameters the opposite way (first S1 and then the integer so it'd be from left to right as we'd call it in C), and if I do switch them, nothing is printed at all while I'm getting a segmentation fault. I don't know what to do, it prints these as output:
welcome to sortMe, please sort me
5
16777216
65536
256
1
117440512
458752
1792
7
50331648
196608
768
mov ecx, [ebp+12] ;put len in ecx, our loop variab
This only moves the address of LEN into ECX not its value! You need to add movzx ecx, byte [ecx]
You also need to define LEN=48
loop loop_1
What's this bizare use of LOOP doing here?
You are mixing bytes and dwords on multiple occasions. You need to rework the code. p.e.
dec ebx ; ebx is now number of times we should go through inner loop
should become
shr ebx,2
This is not correct because you need the address and not the value. Change MOV into LEA.
jle done_2
mov edx, [esi+ebx]
Perhaps you can post your reworked code as an EDIT within your Original question.
Your edited code does not address ALL the problems signaled by user3144770!
The parameters to printf are correct but here are some additional problems with your printArray routine.
Since ESI is an index in an array of dwords you need to scale it up!
push dword [array+esi*4]
Are you sure pusha will save 32 bits ? Perhaps you'd better use pushad
ps Should you decide to rework your code and post the edit then please add the reworked code after the last line of the existing post. This way the original question will continue making sense to people viewing it the first time!

A loop in assembly doesn't work why?

i have problem. I tried build a loop in assembly (nasm,linux). The loop should "cout" number 0 - 10, but it not work and i don't know why. Here is a code :
section .text
global _start
_start:
xor esi,esi
_ccout:
cmp esi,10
jnl _end
inc esi
mov eax,4
mov ebx,1
mov ecx,esi
mov edx,2
int 80h
jmp _ccout
_end:
mov eax,1
int 80h
section .data
Well, the loop is working, but you aren't using the syscall correctly. There are some magic numbers involved here, so let's get that out of the way first:
4 is the syscall number for write
1 is the file descriptor for the standard output
So far, so good. write requires a file descriptor, the address of a buffer and the length of that buffer or the part of it that it's supposed to write to the file descriptor. So, the way this is supposed to look is similar to
mov eax,4 ; write syscall
mov ebx,1 ; stdout
mov ecx,somewhere_in_memory ; buffer
mov edx,1 ; one byte at a time
compare that to your code:
mov eax,4
mov ebx,1
mov ecx,esi ; <-- particularly here
mov edx,2
int 80h
What you are doing there (apart from passing the wrong length) is passing the contents of esi to write as a memory address from which to read the stuff it's supposed to write to stdout. By pure happenstance this doesn't crash, but there's no useful data at that position in memory.
In order to solve this, you will need a location in memory to put it. Moreover, since write works on characters, not numbers, you'll have to to the formatting yourself by adding '0' (which is 48 in ASCII). All in all, it could look something like this:
section .data
text db 0 ; text is a byte in memory
section .text
global _start
_start:
xor esi,esi
_ccout:
cmp esi,10
jnl _end
inc esi
lea eax,['0'+esi] ; print '0' + esi. lea == load effective address
mov [text],al ; is useful here even though we're not really working on addresses
mov eax,4 ; write
mov ebx,1 ; to fd 1 (stdout)
mov ecx,text ; from address text
mov edx,1 ; 1 byte
int 80h
jmp _ccout
_end:
mov [text],byte 10 ; 10 == newline
mov eax,4 ; write that
mov ebx,1 ; like before.
mov ecx,text
mov edx,1
int 80h
mov eax,1
mov ebx,0
int 80h
The output 123456789: is probably not exactly what you want, but you should be able to take it from here. Exercise for the reader and all that.

NASM Linux Assembly Printing Integers

I am trying to print a single digit integer in nasm assembly on linux. What I currently have compiles fine, but nothing is being written to the screen. Can anyone explain to me what I am doing wrong here?
section .text
global _start
_start:
mov ecx, 1 ; stores 1 in rcx
add edx, ecx ; stores ecx in edx
add edx, 30h ; gets the ascii value in edx
mov ecx, edx ; ascii value is now in ecx
jmp write ; jumps to write
write:
mov eax, ecx ; moves ecx to eax for writing
mov eax, 4 ; sys call for write
mov ebx, 1 ; stdout
int 80h ; call kernel
mov eax,1 ; system exit
mov ebx,0 ; exit 0
int 80h ; call the kernel again
This is adding, not storing:
add edx, ecx ; stores ecx in edx
This copies ecx to eax and then overwrites it with 4:
mov eax, ecx ; moves ecx to eax for writing
mov eax, 4 ; sys call for write
EDIT:
For a 'write' system call:
eax = 4
ebx = file descriptor (1 = screen)
ecx = address of string
edx = length of string
After reviewing the other two answers this is what I finally came up with.
sys_exit equ 1
sys_write equ 4
stdout equ 1
section .bss
outputBuffer resb 4
section .text
global _start
_start:
mov ecx, 1 ; Number 1
add ecx, 0x30 ; Add 30 hex for ascii
mov [outputBuffer], ecx ; Save number in buffer
mov ecx, outputBuffer ; Store address of outputBuffer in ecx
mov eax, sys_write ; sys_write
mov ebx, stdout ; to STDOUT
mov edx, 1 ; length = one byte
int 0x80 ; Call the kernel
mov eax, sys_exit ; system exit
mov ebx, 0 ; exit 0
int 0x80 ; call the kernel again
From man 2 write
ssize_t write(int fd, const void *buf, size_t count);
In addition to the other errors that have been pointed out, write() takes a pointer to the data and a length, not an actual byte itself in a register as you are trying to provide.
So you will have to store your data from a register to memory and use that address (or if it's constant as it currently is, don't load the data into a register but load its address instead).

Resources