Question

I'm learning x86 assembly on GNU/Linux, and I'm trying to write a program that reads user input from stdin and prints it on stdout.

The following code does work, but it prints extra characters if the size of the user-entered string is less than 100 bytes.

section .data
    str: db 100    ; Allocate buffer of 100 bytes

section .bss

section .text

global _start

_start:
    mov eax, 3          ; Read user input into str 
    mov ebx, 0          ; |
    mov ecx, str        ; | <- destination
    mov edx, 100        ; | <- length
    int 80h             ; \

    mov eax, 4          ; Print 100 bytes starting from str
    mov ebx, 1          ; |
    mov ecx, str        ; | <- source
    mov edx, 100        ; | <- length
    int 80h             ; \ 

    mov eax, 1          ; Return
    mov ebx, 0          ; | <- return code
    int 80h             ; \

How can I reliably calculate the length of the user-entered string?

How can I avoid printing extra characters?

Was it helpful?

Solution

str: db 100 is wrong. You allocated one byte with the value 100. Correct is: str: times 100 db 0 to allocate 100 bytes with the value 0.

You've got two problems:

1) To get the number of inputted bytes you can evaluate the return value of the read-function (int 80h / fn 3) in EAX.

2) If you input more characters than "allowed" the rest is stored in the input buffer which you have to empty. A possible method to do this is in the following example:

global _start

section .data
    str: times 100 db 0 ; Allocate buffer of 100 bytes
    lf:  db 10          ; LF for full str-buffer

section .bss
    e1_len resd 1
    dummy resd 1

section .text

_start:
    mov eax, 3          ; Read user input into str
    mov ebx, 0          ; |
    mov ecx, str        ; | <- destination
    mov edx, 100        ; | <- length
    int 80h             ; \

    mov [e1_len],eax    ; Store number of inputted bytes
    cmp eax, edx        ; all bytes read?
    jb .2               ; yes: ok
    mov bl,[ecx+eax-1]  ; BL = last byte in buffer
    cmp bl,10           ; LF in buffer?
    je .2               ; yes: ok
    inc DWORD [e1_len]  ; no: length++ (include 'lf')

    .1:                 ; Loop
    mov eax,3           ; SYS_READ
    mov ebx, 0          ; EBX=0: STDIN
    mov ecx, dummy      ; pointer to a temporary buffer
    mov edx, 1          ; read one byte
    int 0x80            ; syscall
    test eax, eax       ; EOF?
    jz .2               ; yes: ok
    mov al,[dummy]      ; AL = character
    cmp al, 10          ; character = LF ?
    jne .1              ; no -> next character
    .2:                 ; end of loop

    mov eax, 4          ; Print 100 bytes starting from str
    mov ebx, 1          ; |
    mov ecx, str        ; | <- source
    mov edx, [e1_len]   ; | <- length
    int 80h             ; \

    mov eax, 1          ; Return
    mov ebx, 0          ; | <- return code
    int 80h             ; \

OTHER TIPS

Here's one way of calculating the length of a string in x86 assembly:

lea esi,[string]
mov ecx,-1    ; Start with ecx = -1
xor eax,eax   ; Clear eax
cld           ; Make scasb scan forward 
repne scasb   ; while (ecx != 0) { ecx--; if (*esi++ == al) break; }
; ecx now contains -1 - (strlen(string) + 1) == -strlen(string) - 2
not ecx       ; Inverting ecx gives us -(-strlen(string) - 2) - 1 == strlen(string) + 1 
dec ecx       ; Subtract 1 to get strlen(string)

This assumes that the string is NUL-terminated ('\0'). If the string uses some other terminator you'll have to initialize al to that value before repne scasb.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top