Assembly on Linux: unexpected behaviour from Assembly [duplicate] - linux

This question already has answers here:
In NASM labels next to each other in memory are printing both strings instead of first one
(1 answer)
How does $ work in NASM, exactly?
(2 answers)
Closed 4 years ago.
running the code below generates a file with Welcome to jj Shashwat as content. what i didn't get is why does it writes Shashwat at the end of the file, Shashwat is in a totally different variable. Any idea why does this happen?
section .text
global _start ;must be declared for using gcc
_start:
;create the file
mov eax, 8
mov ebx, file_name
mov ecx, 0777 ;read, write and execute by all
int 0x80 ;call kernel
mov [fd_out], eax
; close the file
mov eax, 6
mov ebx, [fd_out]
;open the file for reading
mov eax, 5
mov ebx, file_name
mov ecx, 2 ;for read/write access
mov edx, 0777 ;read, write and execute by all
int 0x80
mov [fd_out], eax
; write into the file
mov edx,len ;number of bytes
mov ecx, msg ;message to write
mov ebx, [fd_out] ;file descriptor
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel
; close the file
mov eax, 6
mov ebx, [fd_out]
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
section .data
file_name db 'myfile.txt', 0
msg db 'Welcome to jj', 0
mgafter db ' Shashwat', 0
lntwo equ $-mgafter
len equ $-msg
section .bss
fd_out resb 1
fd_in resb 1
info resb 26

That's because you said len equ $-msg after defining both msg and msgafter, so len is set to the length of both msg and msgafter, making your write call write both strings. This is because len equ $-msg means “set len to be the difference between the current location ($) and the location of msg.”
To fix this, move the len equ $-msg line right after the definition of msg.

Related

Converting user input to all caps in assembly (NASM) [duplicate]

This question already has answers here:
X86 NASM Assembly converting lower to upper and upper to lowercase characters
(5 answers)
X86 Assembly Converting lower-case to uppercase
(1 answer)
Closed 3 years ago.
I want to change the string to all caps, although I am having trouble getting the length of the input. What i have tried so far is moving the address of the message into a registrar then indexing through the string and also increment a counter variable. Then comparing the char in the address to a '.' (signifying the end of the message) and if its found not to be equal it will recall this block of statements. At least this is what I want my code to do. Not sure if this is even the right logic. I know there are alot of errors and its messy but I'm learning so please just focus on my main question. thank you! EDIT: the input i use is 'this is a TEST.'
;nasm 2.11.08
SYS_Write equ 4
SYS_Read equ 3
STDIN equ 0
STDOUT equ 1
section .bss
message resb 15
counter resb 2
section .data
msg1: db 'Enter input (with a period) that I will turn into all capitals!',0xa ;msg for input
len1 equ $- msg1
section .text
global _start
_start:
mov eax, SYS_Write ; The system call for write (sys_write)
mov ebx, STDOUT ; File descriptor 1 - standard output
mov ecx, msg1 ; msg to print
mov edx, len1 ; len of message
int 0x80 ; Call the kernel
mov eax, SYS_Read ;system call to read input
mov ebx, STDIN ;file descriptor
mov ecx, message ;variable for input
mov edx, 15 ;size of message
int 0x80 ;kernel call
mov [counter], byte '0'
getLen:
mov eax, message
add eax, [counter]
inc byte [counter]
cmp eax, '.'
jne getLen
mov eax, SYS_Write ; this is to print the counter to make sure it got the right len
mov ebx, STDOUT
mov ecx, counter
mov edx, 2
int 0x80
jmp end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov eax, [message]
;add eax, counter
cmp eax, 90
jg toUpper
toUpper:
sub eax, 32
mov [message], eax
mov eax, SYS_Write ; The system call for write (sys_write)
mov ebx, STDOUT ; File descriptor 1 - standard output
mov ecx, message ; Put the offset of hello in ecx
mov edx, 10 ; helloLen is a constant, so we don't need to say
int 0x80 ; Call the kernel
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
end:
mov eax,1 ; The system call for exit (sys_exit)
mov ebx,0 ; Exit with return code of 0 (no error)
int 0x80 ;

Read file in a loop in assembly

I am supposed to write a small assembly "program" that simply reads a file using a loop and outputs the contents to STDOUT.
Now, I made a program that can read the file and unfortunately only outputs the first line. I also can't figure out how to use the loop.
This is my very first time working with assembly and I do it because I have to, not because I want to.
Here's my code:
section .text
global _start ;must be declared for using gcc
_start: ;tell linker entry point
;open the file for reading
mov eax, 5
mov ebx, file_name
mov ecx, 0 ;for read only access
mov edx, 0777 ;read, write and execute by all
int 0x80
mov [fd_in], eax
;read from file
mov eax, 3
mov ebx, [fd_in]
mov ecx, info
mov edx, 26
int 0x80
; close the file
mov eax, 6
mov ebx, [fd_in]
; print the info
mov eax, 4
mov ebx, 1
mov ecx, info
mov edx, 26
int 0x80
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
section .data
file_name db './passwd'
section .bss
fd_out resb 1
fd_in resb 1
info resb 26

Assembly: trying to write to file, but text is appending to filename

I'm trying to study assembly, while trying out the example in the tutorials I get stuck. I am compiling this using an ubuntu virtual machine.
Here is the code:
SYS_READ equ 3
SYS_WRITE equ 4
SYS_OPEN equ 5
SYS_CLOSE equ 6
SYS_CREATE equ 8
SYS_EXIT equ 1
section .text
global _start
_start:
mov eax, SYS_CREATE
mov ebx, filename
mov ecx, 0777
int 0x80
mov [fd_out],ebx
mov eax,SYS_WRITE
mov edx,len
mov ecx,msg
mov ebx,[fd_out]
int 0x80
mov eax,SYS_CLOSE
mov ebx,[fd_out]
int 80h
mov eax,SYS_OPEN
mov ebx,filename
mov ecx,0
mov edx,0777
int 0x80
mov [fd_in],eax
mov eax, SYS_READ
mov ebx,[fd_in]
mov ecx,info
mov edx,26
int 0x80
mov eax,SYS_WRITE
mov ebx,1
mov ecx,info
mov edx,26
int 0x80
mov eax,SYS_EXIT
mov ebx,0
int 0x80
section .data
filename db 'test.txt'
msg db 'Hello world file'
len equ $-msg
section .bss
fd_out resb 1
fd_in resb 1
info resb 26
after executing the compiled output, I get a file named test.txtHello world file.
While SYS_WRITE accepts the length of the information in EDX, the function SYS_CREATE needs a pointer to NULL terminated string for the filename.
Your filename, defined as
filename db 'test.txt'
is not NULL terminated and that is why it concatenates with the next string:
msg db 'Hello world file'
The terminating NULL in this case is the next defined:
fd_out resb 1
In order to fix it, simply define the filename with zero terminating byte:
filename db 'test.txt', 0

How to read and display the contents of a text file in nasm?

I want to read and display the contents of a text file using nasm and Linux system calls. My text file is named "new.txt". I wrote the following code and am receiving no output on the terminal.
section .data
line db "This is George,",
db " and his first line.", 0xa, 0
len equ $ - line
line2 db "This is line number 2.", 0xa, 0
len2 equ $ - line2
filename: db 'ThisIsATestFile.txt', 0
section .bss
bssbuf: resb len ;any int will do here, even 0,
file: resb 4 ;since pointer is allocated anyway
global _start
section .text
_start:
; open file in read-only mode
mov eax, 5 ;sys_open file with fd in ebx
mov ebx, filename ;file to be opened
mov ecx, 0 ;O_RDONLY
int 80h
cmp eax, 0 ;check if fd in eax > 0 (ok)
jbe error ;can not open file
mov ebx, eax ;store new (!) fd of the same file
; read from file into bss data buffer
mov eax, 3 ;sys_read
mov ecx, bssbuf ;pointer to destination buffer
mov edx, len ;length of data to be read
int 80h
js error ;file is open but cannot be read
cmp eax, len ;check number of bytes read
jb close ;must close file first
; write bss data buffer to stderr
mov eax, 4 ;sys_write
push ebx ;save fd on stack for sys_close
mov ebx, 2 ;fd of stderr which is unbuffered
mov ecx, bssbuf ;pointer to buffer with data
mov edx, len ;length of data to be written
int 80h
pop ebx ;restore fd in ebx from stack
close:
mov eax, 6 ;sys_close file
int 80h
mov eax, 1 ;sys_exit
mov ebx, 0 ;ok
int 80h
error:
mov ebx, eax ;exit code
mov eax, 1 ;sys_exit
int 80h
When you write
jb close ;must close file first
you, in fact, are jumping to close, not calling it.
Once you reach close, you just exit after you close the file:
close:
mov eax, 6 ;sys_close file
int 80h
mov eax, 1 ;sys_exit
mov ebx, 0 ;ok
int 80h
Perhaps you want to either call close in some way (and then ret from close) or jump back to where you were to continue what you were doing?
Also, keep in mind that jbe is an unsigned comparison, so when you write:
cmp eax, 0 ;check if fd in eax > 0 (ok)
jbe error ;can not open file
You in fact will not detect negative numbers. Consider jle instead. (You can consult this handy resource about jumps to use.)

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