NASM - The Netwide Assembler
NASM Forum => Programming with NASM => Topic started by: dcastellacci on August 21, 2022, 06:23:52 AM
-
Hello
I don't understand why when there are two read input1 and input2 the input1 ends up with the two values of input1 first input and input2 second input.
Thank you
Didier
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [prompt1]
mov edx, len1 ; len
int 80h
mov eax, 3 ; read
mov ebx, 0 ; stdin
lea ecx, [input1]
mov edx, 10 ; len
int 80h
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [outmsg1]
mov edx, len4 ; len
int 80h
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [input1]
mov edx, 10 ; len
int 80h
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [prompt2]
mov edx, len2 ; len
int 80h
mov eax, 3 ; read
mov ebx, 0 ; stdin
lea ecx, [input2]
mov edx, 10 ; len
int 80h
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [outmsg1]
mov edx, len3 ; len
int 80h
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [input2]
mov edx, 10 ; len
int 80h
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [prompt9]
mov edx, len9 ; len
int 80h
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [input1]
;mov edx, 10 ; len
int 80h
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [prompt8]
mov edx, len8 ; len
int 80h
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [input2]
;mov edx, 10 ; len
int 80h
;Exiting
mov eax, 1
mov ebx, 0
int 80h
here is the output
./third-PB-Read
Enter a number: 128
You entered: 128
Enter another number: 150
You entered: 150
Contains input1: 128
150
Contains input2: 150
-
here is the full program
segment .data
prompt1: db "Enter a number: ", 0
len1: equ $-prompt1
prompt2: db "Enter another number: ", 0
len2: equ $-prompt2
outmsg1: db "You entered: ", 0
len3: equ $-outmsg1
outmsg2: db "The sum is: ", 0
len4: equ $-outmsg2
prompt1size1: db "Enter a size of number < 10 for size1: ", 0
len1size1: equ $-prompt1size1
prompt2size2: db "Enter another size of number < 10 for size2: ", 0
len2size2: equ $-prompt2size2
prompt9: db "Contains input1: ", 0
len9: equ $-prompt9
prompt8: db "Contains input2: ", 0
len8: equ $-prompt8
nl: db 10
segment .bss
input1: resb 10
input2: resb 10
segment .text
global _start
_start:
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [prompt1]
mov edx, len1 ; len
int 80h
mov eax, 3 ; read
mov ebx, 0 ; stdin
lea ecx, [input1]
mov edx, 10 ; len
int 80h
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [outmsg1]
mov edx, len4 ; len
int 80h
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [input1]
mov edx, 10 ; len
int 80h
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [prompt2]
mov edx, len2 ; len
int 80h
mov eax, 3 ; read
mov ebx, 0 ; stdin
lea ecx, [input2]
mov edx, 10 ; len
int 80h
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [outmsg1]
mov edx, len3 ; len
int 80h
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [input2]
mov edx, 10 ; len
int 80h
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [prompt9]
mov edx, len9 ; len
int 80h
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [input1]
;mov edx, 10 ; len
int 80h
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [prompt8]
mov edx, len8 ; len
int 80h
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [input2]
;mov edx, 10 ; len
int 80h
;Exiting
mov eax, 1
mov ebx, 0
int 80h
-
Hi Didier,
Welcome to the forum.
I think you may not have a problem... or not the problem you think...
When the pesky user (you) enters the first number... and "enter"... eax will contain the number of characters entered... plus one for the "enter". Save this number! When you print out the contents of the first number, use this number, not 10. I think you've got one number in each buffer, but are printing them both!
Since this is Linux, I can try it, and probably will, but not right now, I just got up to pee and am going back to bed.
Later,
Frank
-
segment .data
prompt1: db "Enter a number: ", 0
len1: equ $-prompt1
prompt2: db "Enter another number: ", 0
len2: equ $-prompt2
outmsg1: db "You entered: ", 0
len3: equ $-outmsg1
outmsg2: db "The sum is: ", 0
len4: equ $-outmsg2
prompt1size1: db "Enter a size of number < 10 for size1: ", 0
len1size1: equ $-prompt1size1
prompt2size2: db "Enter another size of number < 10 for size2: ", 0
len2size2: equ $-prompt2size2
prompt9: db "Contains input1: ", 0
len9: equ $-prompt9
prompt8: db "Contains input2: ", 0
len8: equ $-prompt8
nl: db 10
segment .bss
input1: resb 10
inlen1 resd 1
input2: resb 10
inlen2 resd 1
segment .text
global _start
_start:
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [prompt1]
mov edx, len1 ; len
int 80h
mov eax, 3 ; read
mov ebx, 0 ; stdin
lea ecx, [input1]
mov edx, 10 ; len
:
lea ecx, [prompt1]
mov edx, len1 ; len
int 80h
mov eax, 3 ; read
mov ebx, 0 ; stdin
lea ecx, [input1]
mov edx, 10 ; len
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [prompt1]
mov edx, len1 ; len
int 80h
mov eax, 3 ; read
mov ebx, 0 ; stdin
lea ecx, [input1]
mov edx, 10 ; len
int 80h
mov [inlen1], eax
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [outmsg1]
mov edx, len4 ; len
int 80h
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [input1]
mov edx, [inlen1] ; len
:
mov edx, [inlen1] ; len
int 80h
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [prompt2]
mov edx, len2 ; len
int 80h
mov eax, 3 ; read
mov ebx, 0 ; stdin
lea ecx, [input2]
mov edx, 10 ; len
int 80h
mov [inlen2], eax
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [outmsg1]
mov edx, len3 ; len
int 80h
mov eax, 4 ; write
:
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [input2]
mov edx, [inlen2] ; len
int 80h
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [prompt9]
mov edx, len9 ; len
int 80h
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [input1]
mov edx, [inlen1] ; len
int 80h
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [prompt8]
mov edx, len8 ; len
:
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [input1]
mov edx, [inlen1] ; len
int 80h
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [prompt8]
mov edx, len8 ; len
int 80h
mov eax, 4 ; write
mov ebx, 1 ; stdout
lea ecx, [input2]
mov edx, [inlen2] ; len
int 80h
;Exiting
mov eax, 1
mov ebx, 0
int 80h
Well, I'm pretty sure the above is badly screwed up. I'm having a problem doing something as simple as copying and pasting. If it were right, it would confirm that you don't have a problem.
I notice that you have a prompt for "sum" but don't use it. Do you know how to do that?
Best,
Frank
-
Some comments:
1 - If you are using a distribution in amd64 mode (x86-64), use x86-64 syscalls, not i386;
2 - read syscalls will read blocks of bytes and return its sizes (-1 in case of error);
3 - If you aren't going to write a subroutine, use well documenten macros. Your code will be smaller and with less errors;
4 - Instead of using .data section to store read-only strings, use .rodata;
5 - Keep your labels consistent.
6 - `equ` is a directive, what preceeds it is NOT a label, but a symbol.
Example:
; test.asm
;
; nasm -felf64 -o test.o test.asm
; ld -s -o test test.o
;
bits 64
default rel
%include "macros.inc"
section .rodata
prompt: db "Enter value: "
prompt_len equ $ - prompt
errmsg: db "Error reading value from stdin."
crlf: db `\n`
crlf_len equ $ - crlf
errmsg_len equ $ - errmsg
section .bss
inputbuf: resb 12
inputbuf_len equ $ - inputbuf
section .text
global _start
align 4
_start:
; Write prompt.
lea rsi,[prompt]
mov edx,prompt_len
stdout_write
; Read data from keyboard.
lea rsi,[inputbuf]
push rsi ; save buffer addr to print later
mov edx,inputbuf_len
stdin_read
test eax,eax ; return < 0?
js .error ; yes, error!
pop rsi ; restore buffer addr to print.
mov edx,eax ; size is returned by read syscall
stdout_write
; Print '\n'.
lea rsi,[crlf]
mov edx,crlf_len
stdout_write
exit 0
.error:
add rsp,8 ; we have a saved input buffer ptr on stack.
; dispose of it.
lea rsi,errmsg
mov edx,errmsg_len
stdout_write
exit 1
; macros.inc
; Entry: RSI = buffer ptr
; EDX = buffer size
; Output: EAX = size writen or < 0 if error.
; Destroys: RDI (any other?)
%macro stdout_write 0
mov eax,1 ; write syscall
mov edi,eax ; stdout
syscall
%endmacro
; Entry: RSI = buffer ptr
; EDX = buffer size
; Output: EAX = size read or < 0 if error.
; Destroys: RDI (any other?)
%macro stdin_read 0
xor eax,eax ; read syscall
mov edi,eax ; stdin
syscall
%endmacro
; Entry: (none) - exitcode is taken from macro usage
; Do not return to the caller.
%macro exit 1
mov eax,60
mov edi,%1
syscall
%endmacro
If you need to deal with data read from stdin as if it is an integer, you need to convert to it (atoi). And if you need to print an integer, you need to convert it to a string (itoa?). These routines aren't supplied by syscalls, you need to code your own.
Another note: `.bss` section isn't present on the binary image. Is allocated by the program loader and it is constumary to zero it all at startup. The linker (ld) uses a script filled with some symbols that will help to do this:
extern __bss_start
extern _end
_start:
; Zero the entire BSS.
mov rdi,__bss_start
mov rcx,_end
sub rcx,rdi
inc rcx
xor eax,eax
rep stosb
...
Call "ld --verbose" from your comamand line to see the default ld script.
[]s
Fred
-
Another piece of info that may be useful: As per SysV ABI i386 or x86-64, ESP (or RSP) points to 'argc' integer, and ESP+4 (or RSP+8) points to the begining of char * argv array terminating in 0 (NULL). So... if you wanted to get the input string from command line you could do:
_start:
cmp dword [rsp],2
jne .error_args
mov rsi,[rsp+8+1*8] ; get argv[1].
...
.error_args:
; deal with argc != 2 here
...
This works exactly as `main()`, in C.
-
Some comments:
1 - If you are using a distribution in amd64 mode (x86-64), use x86-64 syscalls, not i386;
2 - read syscalls will read blocks of bytes and return its sizes (-1 in case of error);
3 - If you aren't going to write a subroutine, use well documented macros. Your code will be smaller and with less errors;
4 - Instead of using .data section to store read-only strings, use .rodata;
5 - Keep your labels consistent.
6 - `equ` is a directive, what preceeds it is NOT a label, but a symbol.
Example:
; test.asm
;
; nasm -felf64 -o test.o test.asm
; ld -s -o test test.o
;
bits 64
default rel
%include "macros.inc"
section .rodata
prompt: db "Enter value: "
prompt_len equ $ - prompt
errmsg: db "Error reading value from stdin."
crlf: db `\n`
crlf_len equ $ - crlf
errmsg_len equ $ - errmsg
section .bss
inputbuf: resb 12
inputbuf_len equ $ - inputbuf
section .text
global _start
align 4
_start:
; Write prompt.
lea rsi,[prompt]
mov edx,prompt_len
stdout_write
; Read data from keyboard.
lea rsi,[inputbuf]
push rsi ; save buffer addr to print later
mov edx,inputbuf_len
stdin_read
test eax,eax ; return < 0?
js .error ; yes, error!
pop rsi ; restore buffer addr to print.
mov edx,eax ; size is returned by read syscall
stdout_write
; Print '\n'.
lea rsi,[crlf]
mov edx,crlf_len
stdout_write
exit 0
.error:
add rsp,8 ; we have a saved input buffer ptr on stack.
; dispose of it.
lea rsi,errmsg
mov edx,errmsg_len
stdout_write
exit 1
; macros.inc
; Entry: RSI = buffer ptr
; EDX = buffer size
; Output: EAX = size writen or < 0 if error.
; Destroys: RDI (any other?)
%macro stdout_write 0
mov eax,1 ; write syscall
mov edi,eax ; stdout
syscall
%endmacro
; Entry: RSI = buffer ptr
; EDX = buffer size
; Output: EAX = size read or < 0 if error.
; Destroys: RDI (any other?)
%macro stdin_read 0
xor eax,eax ; read syscall
mov edi,eax ; stdin
syscall
%endmacro
; Entry: (none) - exitcode is taken from macro usage
; Do not return to the caller.
%macro exit 1
mov eax,60
mov edi,%1
syscall
%endmacro
If you need to deal with data read from stdin as if it is an integer, you need to convert to it (atoi). And if you need to print an integer, you need to convert it to a string (itoa?). These routines aren't supplied by syscalls, you need to code your own.
Another note: `.bss` section isn't present on the binary image. Is allocated by the program loader and it is constumary to zero it all at startup. The linker (ld) uses a script filled with some symbols that will help to do this:
extern __bss_start
extern _end
_start:
; Zero the entire BSS.
mov rdi,__bss_start
mov rcx,_end
sub rcx,rdi
inc rcx
xor eax,eax
rep stosb
...
Call "ld --verbose" from your comamand line to see the default ld script.
[]s
Fred
-
Some comments:
1 - If you are using a distribution in amd64 mode (x86-64), use x86-64 syscalls, not i386;
2 - read syscalls will read blocks of bytes and return its sizes (-1 in case of error);
3 - If you aren't going to write a subroutine, use well documenten macros. Your code will be smaller and with less errors;
4 - Instead of using .data section to store read-only strings, use .rodata;
5 - Keep your labels consistent.
6 - `equ` is a directive, what preceeds it is NOT a label, but a symbol.
Example:
; test.asm
;
; nasm -felf64 -o test.o test.asm
; ld -s -o test test.o
;
bits 64
default rel ; to use RIP relative effective addresses (permit ASLR).
%include "macros.inc"
section .rodata
prompt: db "Enter value: "
prompt_len equ $ - prompt
errmsg: db "Error reading value from stdin."
crlf: db `\n`
crlf_len equ $ - crlf
errmsg_len equ $ - errmsg
section .bss
inputbuf: resb 12
inputbuf_len equ $ - inputbuf
section .text
global _start
align 4
_start:
; Write prompt.
lea rsi,[prompt]
mov edx,prompt_len
stdout_write
; Read data from keyboard.
lea rsi,[inputbuf]
push rsi ; save buffer addr to print later
mov edx,inputbuf_len
stdin_read
test eax,eax ; return < 0?
js .error ; yes, error!
pop rsi ; restore buffer addr to print.
mov edx,eax ; size is returned by read syscall
stdout_write
; Print '\n'.
lea rsi,[crlf]
mov edx,crlf_len
stdout_write
exit 0
.error:
add rsp,8 ; we have a saved input buffer ptr on stack.
; dispose of it.
lea rsi,errmsg
mov edx,errmsg_len
stdout_write
exit 1
; macros.inc
; Entry: RSI = buffer ptr
; EDX = buffer size
; Output: EAX = size writen or < 0 if error.
; Destroys: RDI (any other?)
%macro stdout_write 0
mov eax,1 ; write syscall
mov edi,eax ; stdout
syscall
%endmacro
; Entry: RSI = buffer ptr
; EDX = buffer size
; Output: EAX = size read or < 0 if error.
; Destroys: RDI (any other?)
%macro stdin_read 0
xor eax,eax ; read syscall
mov edi,eax ; stdin
syscall
%endmacro
; Entry: (none) - exitcode is taken from macro usage
; Do not return to the caller.
%macro exit 1
mov eax,60
mov edi,%1
syscall
%endmacro
If you need to deal with data read from stdin as if it is an integer, you need to convert to it (atoi). And if you need to print an integer, you need to convert it to a string (itoa?). These routines aren't supplied by syscalls, you need to code your own.
Another note: `.bss` section isn't present on the binary image. Is allocated by the program loader and it is constumary to zero it all at startup. The linker (ld) uses a script filled with some symbols that will help to do this:
extern __bss_start
extern _end
_start:
; Zero the entire BSS.
mov rdi,__bss_start
mov rcx,_end
sub rcx,rdi
inc rcx
xor eax,eax
rep stosb
...
Call "ld --verbose" from your comamand line to see the default ld script.
[]s
Fred
-
Wow! Thank you, Fred!
Best,
Frank