Author Topic: Title : difficulty with two consecutive reads  (Read 9584 times)

Offline dcastellacci

  • Jr. Member
  • *
  • Posts: 2
Title : difficulty with two consecutive reads
« 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

Code: [Select]
    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

Code: [Select]
./third-PB-Read
Enter a number: 128
You entered: 128
Enter another number: 150
You entered: 150
Contains input1: 128
150
Contains input2: 150


Offline dcastellacci

  • Jr. Member
  • *
  • Posts: 2
Re: Title : difficulty with two consecutive reads
« Reply #1 on: August 21, 2022, 06:36:48 AM »

here is the full program

Code: [Select]

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

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Title : difficulty with two consecutive reads
« Reply #2 on: August 21, 2022, 08:37:46 AM »
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


Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Title : difficulty with two consecutive reads
« Reply #3 on: August 24, 2022, 04:45:14 AM »
Code: [Select]
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


Offline fredericopissarra

  • Full Member
  • **
  • Posts: 373
  • Country: br
Re: Title : difficulty with two consecutive reads
« Reply #4 on: August 24, 2022, 03:13:56 PM »
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:
Code: [Select]
; 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
Code: [Select]
; 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:
Code: [Select]
  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
« Last Edit: August 24, 2022, 03:29:58 PM by fredericopissarra »

Offline fredericopissarra

  • Full Member
  • **
  • Posts: 373
  • Country: br
Re: Title : difficulty with two consecutive reads
« Reply #5 on: August 24, 2022, 03:38:16 PM »
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:
Code: [Select]
_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.

Offline fredericopissarra

  • Full Member
  • **
  • Posts: 373
  • Country: br
Re: Title : difficulty with two consecutive reads
« Reply #6 on: August 24, 2022, 03:56:30 PM »
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:
Code: [Select]
; 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
Code: [Select]
; 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:
Code: [Select]
  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

Offline fredericopissarra

  • Full Member
  • **
  • Posts: 373
  • Country: br
Re: Title : difficulty with two consecutive reads
« Reply #7 on: August 24, 2022, 03:59:10 PM »
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:
Code: [Select]
; 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
Code: [Select]
; 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:
Code: [Select]
  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

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Title : difficulty with two consecutive reads
« Reply #8 on: August 24, 2022, 05:11:35 PM »
Wow! Thank you, Fred!

Best,
Frank