nasm program printing more arguments than it should - linux

I am writing a simple program where I am supposed to get the first command line argument and print it out to the standard output.
My code looks like this:
section .bss
env resb 100
section .text
global _start
_start:
mov rbp, rsp
add rbp, 16
mov rsi, arg
mov rsi, [rbp]
mov rax, 1
mov rdi, 1
mov rdx, 100
syscall
So when I call my program from the Linux terminal, like this: ./program hello, I expect it to print out "hello". But the output looks like this: helloLC_PAPER=bs_BA.UTF-8XDG_VTNR=7LC_ADDRESS=bs_BA.UTF-8SSH_AGENT_PID=1483XDG_SESSION_ID=c2LC.
I understand that these are the environmental variables, but I just can't figure out why they get printed out.
Any help is appreciated.

Actually if you check carefully you will observe that 100 characters are printed, starting from the address of "hello" in the memory.
Replace
mov rdx, 100
with
mov rdx, 5 ; len of "hello", instead of 100

Related

NASM - How can I solve the input reading problem from the terminal? [duplicate]

This question already has answers here:
Read STDIN using syscall READ in Linux: unconsumed input is sent to bash
(2 answers)
Closed 4 months ago.
section .data
yourinputis db "your input is =",0
len equ $ - yourinputis
section .bss
msginput resb 10
section .text
global _start
_start:
mov eax,3 ;read syscall
mov ebx,2
mov ecx,msginput
mov edx,9 ; I don't know that is correct?
int 80h
mov eax,4 ;write syscall
mov ebx,1
mov ecx,yourinputis
mov edx,len
int 80h
mov eax,4 ;write syscall
mov ebx,1
mov ecx,msginput
mov edx,10
int 80h
exit:
mov eax,1 ;exit syscall
xor ebx,ebx
int 80h
This code working very well. But It is so terrible bug(for me:(). If I enter an input longer than 10 --->
$./mycode
012345678rm mycode
your input is 012345678$rm mycode
$
This is happening. And of course "mycode" is not exist right now.
What should I do?
EDIT:The entered input is correctly printed on the screen. But if you enter a long input, it moves after the 9th character to the shell and runs it.
In the example, the "rm mycode" after "012345678" is running in the shell.
If you enter more than 9 characters, they're left in the terminal driver's input buffer. When the program exits, the shell reads from the terminal and tries to execute the rest of the line as a command.
To prevent this, your program should keep reading in a loop until it gets a newline.
You can read the characters one by one until you reach 0x0a. Something like:
_read:
mov esi, msginput
_loop:
mov eax,3 ;read syscall
mov ebx,0
mov ecx, esi
mov edx,1 ; I don't know that is correct?
int 80h
cmp byte[esi], 0x0a
je end
inc esi
jmp _loop
end:
ret
You would have to increase the size of msginput tho.
IMPORTANT: Do note that this is not the efficient way to do this (see the comments), it is only put here as an example to the answer above.

x86_64 Warning : character constant too long [-w+other] (nasm)

I am writing a compiler in attempt to switch my programming language from interpreted to compiled
this is the code my script generated:
section .bss
digitSpace resb 100
digitSpacePos resb 8
string_at_index_0 resb 12
string_at_index_0_len resb 4
section .data
section .text
global _start
_start:
mov rax, "Hello world"
mov [string_at_index_0], rax
mov byte [string_at_index_0_len], 13
mov rax, 1
mov rdi, 1
mov rsi, string_at_index_0
mov rdx, string_at_index_0_len
syscall
mov rax, 60
mov rdi, 0
syscall
when i run this code with nasm -f elf64 -o test.o test.asm i get this warning:
warning:character constant too long [-w+other]
can anyone help me with this , and also if anyone could suggest a better way to output a Hello world that would be helpful too!
mov rax, "Hello world"
RAX is an 64-bit (8 byte) register, you are trying to put 11 bytes into it.
Here is a simple hello world:
As can be seen you don't want to put the message inside the register, you want to put a pointer to the message into rsi.
section .data
msg: db "Hello World"
section .text
global _start
_start:
mov rax, 1 ; write function
mov rdi, 1 ; to stdout
mov rsi, msg ; pointer to message
mov rdx, 11 ; length of the message
syscall ; write
Ideally, your compiler should declare string literals in .data section and pass pointers to them when using them in functions.

Print new line in assembly

I am beginner at assembly language and I don't understand why the code#1 works and code#2 doesn't... Does anybody know how to help me?
I want to print a new line, so i have copied this code#1:
section .data
newline_char: db 10
section .text
global _start
print_newline:
mov rax, 1
mov rdi, 1
mov rsi, newline_char
mov rdx, 1
syscall
But if i try the code#2, it doesn't work and the newline is not printed:
; I have removed the newline_char from here
section .text
global _start
print_newline:
mov rax, 1
mov rdi, 1
mov rsi, 10 ; I tried to put immediatly in here and have already tested '0x0a' '0ah'
mov rdx, 1
syscall
Does anyone know what I am doing wrong?

Update the string that has already been printed every second in NASM

I am completely new to the assembly thing and googling for several hours and searching on SO didn't clear things out so I came to ask here.
What I want to achieve:
[first second]: hello (stays on the screen for 1 second)
[second second]: world (hello disappeared and now we have `world` in place of it)
And this flow is in an infinite loop
In other words, I want my terminal's stdout to flicker(change) between hello and world without appending any newlines, writing strings or any other things, I just want the existing, already printed text to be replaced with some another text.
I have written the infinite loop that will print hello, then wait for a second, then print world, and wait for a second. I have also put this code in an infinite loop.
Here is the code I have as of now:
section .data
hello db "hello",10,0
world db "world",10,0
delay dq 1,0
section .text
global _start
_start:
mov rax, 1
mov rdi, 1
mov rsi, hello
mov rdx, 6
syscall
mov rax, 35
mov rdi, delay
mov rsi, 0
syscall
mov rax, 1
mov rdi, 1
mov rsi, world
mov rdx, 6
syscall
mov rax, 35
mov rdi, delay
mov rsi, 0
syscall
call _start
Note that I use elf64 asm format and it is highly appreciated to suggest a solution in that format.
Print a \r carriage return (ASCII code 13) to put the cursor at the beginning of the line without scrolling the terminal the way \n line feed (ASCII 10) does.
Then you can overwrite the last thing you wrote. If it's shorter, you can print spaces after your visible characters to "erase" the later characters still there.
e.g. since both words are the same length you could do this:
section .rodata
hello db 13, "hello" ; `\rhello`
hello_len equ $ - hello
world db 13, "world"
world_len equ $ - world
Notice that , 0 is not needed in your data because you're passing these buffers to write not printf, so they don't need to be 0-terminated implicit-length C strings. You also don't need to hard-code mov rdx, 6, you can use mov rdx, hello_len with the assembler calculating that for you.
For the sleeping part, you can use the sleep libc function, but for raw system calls you'll have to use nanosleep. (Like you're already doing.)
For the looping, don't use call _start; use jmp. You don't want to push a return address; that would eventually stack overflow (after about 1 million seconds: 8MiB stack size limit and call pushes an 8-byte return address.)
Solved this using helpful guidance of Peter Cordes.
The working code looks like this:
section .data
hello db "hello",13,0
world db "world",13,0
delay dq 1,0
section .text
global _start
_start:
mov rax, 1
mov rdi, 1
mov rsi, hello
mov rdx, 6
syscall
mov rax, 35
mov rdi, delay
mov rsi, 0
syscall
mov rax, 1
mov rdi, 1
mov rsi, world
mov rdx, 6
syscall
mov rax, 35
mov rdi, delay
mov rsi, 0
syscall
jmp _start

How to read each char from string NASM assembly 64bit linux

I have a 64bit NASM assembly assignment to capitalize (all letters should be lowercase,except those which are at the beginning of the sentence) letters of input text. I'm totally new to assembler and I can't find anywhere how I should read each char from string incrementally, when I read the text like this:
section .data
prompt db "Enter your text: ", 10
length equ $ - prompt
text times 255 db 0
textsize equ $ - text
section .text
global main
main:
mov rax, 1
mov rdi, 1
mov rsi, prompt
mov rdx, length
syscall ;print prompt
mov rax, 0
mov rdi, 0
mov rsi, text
mov rdx, textsize
syscall ;read text input from keyboard
exit:
mov rax, 60
mov rdi, 0
syscall
Also, I'm not sure how to find out when the text is over, so I could know when I have to exit the program. Should I do some operations with text size or there is some king of special symbol which shows the EOL? Thank you for your answers.
After returning from sys_read (syscall rax=0) RAX register should contain the number of characters actually has been read. Notice, that in Linux, sys_read will return when /n is accepted, even if there is more place in the buffer provided.
Then organize a loop from 0 to RAX and process each character the way you want:
mov byte ptr [text+rax], 0 ; make the string zero terminated for future use.
mov rcx, rax ; rcx will be the character counter.
mov rsi, text ; a pointer to the current character. Start from the beginning.
process_loop:
mov al, [rsi] ; is it correct NASM syntax?
; here process al, according to your needs...
; .....
inc rsi
dec rcx
jnz process_loop
The above code can be optimized of course, for example to use string instructions or loop instructions, but IMO, this way is better for a beginner.

Resources