How to save a file in assembly language with nasm in Linux x86? - linux

I'm just wondering how I can throw a buffer to a file. I know I can set up the registers like:
mov eax, 4
mov ebx, (file descriptor here)
mov ecx, myBuffer
mov edx, myBufferLen
int 80h
and then close the file with:
mov eax, 6
int 80h
but I'm not sure how to get the file descriptor. Someone told me that whenever you open a file, after calling the service dispatcher, the eax has the file descriptor. Whatever I try, it doesn't create a new file or save the current one.

mov eax, 5 ; __NR_open
mov ebx, filename ; zero terminated!
mov ecx, 2 ; O_WRITE? Check me on this!
mov edx, 777q ; permissions - Check me on this, too!
int 80h
; did we succeed?
cmp eax, -4096
ja exit
mov [descriptor], eax
; and so on...
;...
xor eax, eax ; claim no error
exit:
mov ebx, eax
neg ebx
mov eax, 1 ; __NR_exit
int 80h
I'm uncertain on the "magic numbers" for open flags and permissions, and too lazy to look them up right now (fs.h?). You may need to "or" the open flags with O_CREATE to create a new file(?). The trick at "exit:" negates the (negative) ERRNO (if any) so you can read it easily with "echo $?". Something like that...

Thanks to #gnometorule for the solution. So this is how you store a buffer into file:
in this case you are receiving the file name as a first parameter when you run the program.
section .text
global _start
_start:
pop ebx ; this is the amount of parameter received (in this case 2)
pop ebx ; this is the direction of our program
pop ebx ; this is the first parameter (our file name eg. "text.txt")
so we open it and move it to a buffer to edit or whatever we want with it.
textEdit:
;we open the file
mov eax, 5
push ebx ; we save the file name in the stack for later use
mov ecx,0
int 80h
; and then we move the information read to buffer
mov eax, 3
mov ebx, eax ; really dont know how this works, but it does.
mov ecx, fileBuffer
mov edx, fileBufferSize
int 80h
now fileBuffer (wich is a buffer defined in section .bss) has what we had in the file we opened. Here you can edit the information. When we want to save it back to the file it goes like this:
saveFile:
;open the file
mov eax, 5
pop ebx ; the file name was stored in the stack,
push ebx ; so we retrieve it and save it back for later use
mov ecx, 2 ; ecx has the access mode ("2"aloud us to read/write)
mov edx, $0666
int 80h
;now we are going to write to the file
mov ebx, eax ; eax has the file descriptor we opened. so we move it to ebx.
mov eax, 4 ; we are going to use the write service (#4)
mov ecx, fileBuffer ; ecx has the adress of what we want to write
mov edx, fileBufferSize ; edx has the amount of bytes we want to write
int 80h
; close the file
mov eax, 6
int 80h
jmp exit ; jump wherever you want, or end your program... etc.
This worked for me.

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.

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.

Register and variables not saving state after jump

I'm trying to learn NASM. I want to write a procedure to get one character at a time from the console until a newline (0xA) is encountered using only kernel calls. So far I have
global _start
section .data
sys_read equ 3
sys_write equ 4
stdin equ 0
stdout equ 1
section .bss
line resb 11
index resb 4
section .text
_start:
push ebp
mov ebp, esp
call _readLine
afterReadLine:
call _printLine
mov esp, ebp
pop ebp
jmp exit
_readLine:
; Reads into line until new line (0xA)
; Number of bytes read will be stored in index when _readLine returns
mov eax, sys_read ; syscall to read
mov ebx, stdin ; stdin
mov edx, [index] ; put index into edx
mov ecx, dword line ; put line addr in ecx
add ecx, edx ; add index to addr in ecx
mov edx, 1 ; read one char
int 0x80 ; call kernel to read char
mov ecx, [index] ; put index into ecx
cmp dword [line + ecx], 0xA ; compare value at line + ecx to new line char
inc byte [index] ; increment index
je afterReadLine ; if last char is newline return
jne _readLine ; if last char is not new line, loop
_printLine:
mov eax, sys_write
mov ebx, stdout
mov ecx, line
mov edx, [index]
int 0x80
ret
exit:
mov eax, 01h ; exit()
xor ebx, ebx ; errno
int 80h
When I test against the value stored in the index variable at the end, it always equals 0. I tried moving the value of index into eax, but it's also zero after the jump. I tried using the ret keyword, but that also seemed to overwrite my values. What is the best practice way to return the value of characters read from this procedure?
EDIT:
I tried the following and I'm still not getting any output. With input "abcd[newline]" the program outputs "abcd" if I hardcode the value of 4 in edx in the _printLine procedure, but as written won't output anything.
global _start
section .data
sys_read equ 3
sys_write equ 4
stdin equ 0
stdout equ 1
bytesRead dd 0
termios: times 36 db 0
ICANON: equ 1<<1
ECHO: equ 1<<3
section .bss
line resb 11
index resb 4
section .text
_start:
push ebp
mov ebp, esp
call canonical_off
call echo_off
call _readLine
call _printLine
call canonical_on
call echo_on
mov esp, ebp
pop ebp
jmp exit
_readLine:
; Reads into line until new line (0xA)
; Number of bytes read will be stored in bytesRead when _readLine returns
mov eax, sys_read ; syscall to read
mov ebx, stdin ; stdin
mov edx, [index] ; put index into edx
mov ecx, dword line ; put line addr in ecx
add ecx, edx ; add index to addr in ecx
mov edx, 1 ; read one char
int 0x80 ; call kernel to read char
mov ecx, [index] ; put index into ecx
cmp dword [line + ecx], 0xA ; compare value at line + ecx to new line char
inc byte [index] ; increment index
jne _readLine ; if last char is not new line, loop
ret
_printLine:
mov eax, sys_write
mov ebx, stdout
mov ecx, line
mov edx, [index] ; Works if hardcoded 4 here!
int 0x80
ret
canonical_off:
call read_stdin_termios
; clear canonical bit in local mode flags
;push rax
mov eax, ICANON
not eax
and [termios+12], eax
;pop rax
call write_stdin_termios
ret
echo_off:
call read_stdin_termios
; clear echo bit in local mode flags
;push rax
mov eax, ECHO
not eax
and [termios+12], eax
;pop rax
call write_stdin_termios
ret
canonical_on:
call read_stdin_termios
; set canonical bit in local mode flags
or dword [termios+12], ICANON
call write_stdin_termios
ret
echo_on:
call read_stdin_termios
; set echo bit in local mode flags
or dword [termios+12], ECHO
call write_stdin_termios
ret
read_stdin_termios:
; push rax
; push rbx
; push rcx
;push rdx
mov eax, 36h
mov ebx, stdin
mov ecx, 5401h
mov edx, termios
int 80h
;pop rdx
; pop rcx
;pop rbx
;pop rax
ret
write_stdin_termios:
; push rax
;push rbx
;push rcx
; push rdx
mov eax, 36h
mov ebx, stdin
mov ecx, 5402h
mov edx, termios
int 80h
;pop rdx
;pop rcx
; pop rbx
;pop rax
ret
exit:
mov eax, 01h ; exit()
xor ebx, ebx ; errno
int 80h
link here http://ideone.com/Lw3fyV
First off, you are calling _readLine but not returning from it, instead you are jumping to the label after call _readLine conveniently called afterReadLine. You should use ret to exit from your function.
Now to your question. By default, the terminal is in canonical mode (Cooked mode), meaning all input is buffered. The system will fill your buffer until the return key is pressed and adds 0xA to the end of the buffer.
What you want is non-canonical mode (raw mode). This means the system does not process the key presses but passes it on to you.
How do i read single character input from keyboard using nasm (assembly) under ubuntu?
By switching to raw mode, you can get each character pressed until the return key and do what you will with it.

Which Linux system calls should I use to read raw characters from stdin?

I'm trying to port my stdrepl library to FASM for learning purposes. I know that the GNU readline library already does what I'm trying to do, but I want to learn how to write non-trivial programs in assembly.
In node.js I can easily create a tty by writing:
var stdin = process.stdin;
stdin.setEncoding("utf8");
stdin.setRawMode(true);
stdin.resume();
How do I achieve the same results in pure assembly. I tried reading one byte from stdin at a time in a loop as follows, but it doesn't return the byte right after I hit a key:
oct db ?
mov eax, 3
xor ebx, ebx
mov ecx, oct
mov edx, 1
Note that the data definition oct is not a part of the loop, so please don't smite me for that. I know how to structure an assembly program.
Sorry for the delay (I really should "register" here - that'll get me "notifications", right?). As I said, it's rudimentary and imperfect. Some of the "usual" stuff may be defined elsewhere, but I think you can figure out how to get it to assemble. Just call it - no parameters - and the key is returned in al. Hope it's some use to you!
;-----------------------------
; ioctl subfunctions
%define TCGETS 0x5401 ; tty-"magic"
%define TCSETS 0x5402
; flags for 'em
%define ICANON 2 ;.Do erase and kill processing.
%define ECHO 8 ;.Enable echo.
struc termios
alignb 4
.c_iflag: resd 1 ; input mode flags
.c_oflag: resd 1 ; output mode flags
.c_cflag: resd 1 ; control mode flags
.c_lflag: resd 1 ; local mode flags
.c_line: resb 1 ; line discipline
.c_cc: resb 19 ; control characters
endstruc
;---------------------------------
getc:
push ebp
mov ebp, esp
sub esp, termios_size ; make a place for current kbd mode
push edx
push ecx
push ebx
mov eax, __NR_ioctl ; get current mode
mov ebx, STDIN
mov ecx, TCGETS
lea edx, [ebp - termios_size]
int 80h
; monkey with it
and dword [ebp - termios_size + termios.c_lflag], ~(ICANON | ECHO)
mov eax, __NR_ioctl
mov ebx, STDIN
mov ecx, TCSETS
lea edx, [ebp - termios_size]
int 80h
xor eax, eax
push eax ; this is the buffer to read into
mov eax, __NR_read
mov ebx, STDIN
mov ecx, esp ; character goes on the stack
mov edx, 1 ; just one
int 80h ; do it
; restore normal kbd mode
or dword [ebp - termios_size + termios.c_lflag], ICANON | ECHO
mov eax, __NR_ioctl
mov ebx, STDIN
mov ecx, TCSETS
lea edx, [ebp - termios_size]
int 80h
pop eax ; get character into al
pop ebx ; restore caller's regs
pop ecx
pop edx
mov esp, ebp ; leave
pop ebp
ret
;-------------------------

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