3
\$\begingroup\$

So I am working on an x86 Assembly program for Linux using NASM. This program basically asks the user for their name and their favorite color. After doing this and storing the two strings in variables declared in the .bss section, the program prints "No way name of user, favorite color is my favorite color, too!

The problem I am having is that there are enormous spaces in the output because I do not know how long the string was that the user entered, only the length that I declared the buffer to be.

section .data
    greet:       db 'Hello!', 0Ah, 'What is your name?', 0Ah  ;simple greeting
    greetL:      equ $-greet                                  ;greet length
    colorQ:      db 'What is your favorite color?'            ;color question
    colorL:      equ $-colorQ                                 ;colorQ length
    suprise1:    db 'No way '                               
    suprise1L    equ $-suprise1
    suprise3:    db ' is my favorite color, too!', 0Ah

section .bss 
    name:        resb 20                                      ;user's name
    color:       resb 15                                      ;user's color

section .text
    global _start
_start:

    greeting:
         mov eax, 4
         mov ebx, 1
         mov ecx, greet
         mov edx, greetL
         int 80                                               ;print greet

    getname:
         mov eax, 3
         mov ebx, 0
         mov ecx, name
         mov edx, 20
         int 80                                               ;get name

    askcolor:
         ;asks the user's favorite color using colorQ

    getcolor: 
         mov eax, 3
         mov ebx, 0
         mov ecx, name
         mov edx, 20
         int 80

    thesuprise:
         mov eax, 4
         mov ebx, 1
         mov ecx, suprise1
         mov edx, suprise1L
         int 80 

         mov eax, 4
         mov ebx, 1
         mov ecx, name
         mov edx, 20
         int 80 

         ;write the color

         ;write the "suprise" 3

         mov eax, 1
         mov ebx, 0
         int 80

The code for what I am doing is above. Does anyone have a good method for finding the length of the entered string, or of taking in a character at a time to find out the length of the string?

\$\endgroup\$

closed as off topic by Adam Mar 3 '13 at 10:02

Questions on Code Review Stack Exchange are expected to relate to code review request within the scope defined by the community. Consider editing the question or leaving comments for improvement if you believe the question can be reworded to fit within the scope. Read more about reopening questions here. If this question can be reworded to fit the rules in the help center, please edit the question.

  • \$\begingroup\$ The thing is, you can't really do that. You would either have to allocate enough memory for what you would expect at most, or you could ask the user for how much space should be allocated. The second option is not very practical nor safe. Just figure out what limit you would want to account for and handle that. Use the appropriate syscalls to ensure you don't exceed that limit. I generally would use BUFSIZ (typically 512). \$\endgroup\$ – Jeff Mercado Oct 23 '11 at 19:39
  • \$\begingroup\$ I'm all in favor of doing this sort of thing in assembly as a learning exercise, but interfacing with syscalls via int 80h is not the most interesting use of assembly. Things like doing file I/O or maintaining dynamically-resized buffers make a lot more sense in C. What you will have with this approach is an assembly program that calls C functions (either through a software interrupt in the case of syscalls or call instruction in the case of libc), and that won't really teach you idiomatic x86 assembly. \$\endgroup\$ – asveikau Oct 24 '11 at 1:37
  • 2
    \$\begingroup\$ The read system call returns the number of characters read (or the error code negated - you should check for this), save that count and use it when displaying. As @JeffMercado says it's not unreasonable to limit inputting to something like 512 - who has a favorite color with a longer length than that? Alternatively you can read characters in a loop where you do the equivalent of realloc each time the buffer is filled, but this requires more care. \$\endgroup\$ – user786653 Oct 24 '11 at 5:51
  • \$\begingroup\$ Bug solving and code requests like this belong on Stack Overflow. \$\endgroup\$ – Cees Timmerman Oct 24 '14 at 10:33
2
\$\begingroup\$

I have an answer in x86 tasm and written under Windows, so I'm not sure if this will help, apologies if it doesn't. Maybe the way its done will give you some ideas.

.model small
.stack 100h
.data


    colour db 00001111b
    input db 10, 0, " " ; 

.code

main:

    call initsegs
    call readstring
    call printstring
    call exit



PROC printstring 

    push bx dx cx ax bp
    mov bx, 1; 1st (after zero) byte of input we are after, the length
    xor dx, dx; make sure dx contains zero before we play with dh and dl

    mov dl, input[bx]
    mov cx, dx; cx now has the 2nd byte value in the string, ie the length

    mov ah, 13h ; int 13h of 10h, print a string
    mov al, 1 ; write mode: colour on bl    
    mov bh, 0 ; video page zero
    mov bl, colour; colour attribute

    mov dh, 10; row
    mov dl, 10; column
    mov bp, offset input ; es:bp needs to point at string..this points to string but includes its max and length at the start

    add bp, 2 ; skip the first two elements which will be the length and amount used
    int 10h;


    pop bp ax cx dx bx

    ret

ENDP printstring


PROC readstring 

    push ax dx


    mov ah, 0ah ; function a of 21h - read a string
    mov dx, offset input ; reads string into DS:DX so DX needs be offset of string variable

    int 21h ; call the interrupt

    pop dx ax

    ret

ENDP readstring



PROC exit

    mov ah, 4ch
    INT 21h

    RET

ENDP Exit


PROC initsegs

    push ax

    mov ax, @DATA
    mov ds, ax
    mov es, ax

    pop ax

    RET

ENDP initsegs



end main
\$\endgroup\$
1
\$\begingroup\$

To allocate memory without using the clib, you need to adjust the system break. I explain it here: NASM - Linux Dynamic Memory Allocation/Read file

sys_exit        equ     1
sys_read        equ     3
sys_write       equ     4
sys_brk         equ     45
stdin           equ     0
stdout          equ     1

section .data
szGreet         db  'Hello!', 0Ah, 'What is your name? :',0
Greet_len       equ $-szGreet     
szColor         db  'What is your favorite color? :',0 
Color_len       equ $ - szColor
szSpace         db ",", 32, 0
suprise1:       db 'No way ',0                             
suprise1L       equ $-suprise1
suprise3:       db ' is my favorite color, too!', 0Ah,0
surprise3L      equ $-suprise3

section .bss
lpName:        resb 20                                      ;user's name
name_len       equ    $ - lpName    
lpColor:       resb 15             
color_len      equ $-lpColor                         ;user's color
TempBuf        resd 1

section .text
    global _start

_start:

.greeting:
    mov     edx, Greet_len  
    mov     ecx, szGreet 
    call    WriteText                       ; Say hello, ask for name

.getname:    
    mov     edx, name_len 
    mov     ecx, lpName
    call    ReadText                        ; Read name into buffer

.getcolor: 
    mov     edx, Color_len              
    mov     ecx, szColor
    call    WriteText                       ; Ask for fav color

    mov     edx, color_len
    mov     ecx, lpColor
    call    ReadText                        ; Read color into buffer

.GetLen:
    mov     edi, lpName
    call    GetStrlen                       ; length of inputed name
    mov     esi, edx

    mov     edi, lpColor                    ; length of inputed color
    call    GetStrlen

    add     esi, edx                        ; Name len + Color len
    add     esi, suprise1L                  ; surprise1 text len
    add     esi, surprise3L                 ; surprise3 text len
    add     esi, 2                          ; lenght of comma and space
    call    Alloc                           ;
    mov     [TempBuf], eax                  ; address of the end of bss section

.thesuprise:
    push    suprise3
    push    lpColor
    push    szSpace
    push    lpName
    push    suprise1
    push    dword [TempBuf]
    push    5
    call    szMultiCat                      ; concat all strings together
    add     esp, 4 * 7 

    mov     ecx, dword [TempBuf]
    mov     edx, esi
    call    WriteText                       ; print to terminal

    ;~ "free" memory
    mov     ebx, [TempBuf]
    mov     eax, sys_brk                    ; restore system break
    int     80H

    mov     eax, sys_exit
    mov     ebx, 0
    int     80H

;~ #########################################
WriteText:    
    mov     ebx, stdout
    mov     eax, sys_write
    int     80H 
    ret

;~ #########################################    
ReadText:
    mov     ebx, stdin 
    mov     eax, sys_read       
    int     80H    
    ret  

;~ #########################################     
GetStrlen:
    xor     ecx, ecx
    not     ecx
    xor     eax, eax
    cld
    repne   scasb
    mov     byte [edi - 2], 0               ; null terminate string
    not     ecx
    lea     edx, [ecx - 1]
    ret

;~ ######################################### 
Alloc:
    ; esi == size to allcocate

    ;~ Get end of bss section
    xor     ebx, ebx
    mov     eax, sys_brk
    int     80H
    push    eax

    ; extend it by size
    mov     ebx, eax
    add     ebx, esi
    mov     eax, sys_brk
    int     80H

    pop     eax                             ; return address of break
    ret

;  #####################################################################
;  Name       : szMultiCat
;  Arguments  : esp + 4 = 
;               esp + 8 = 
;               esp + 12 = 
;               esp + 16 =
;  Description: Concats multiple NULL terminated strings together
;  Returns    : Nothing
;
szMultiCat: 
    push    ebx
    push    esi
    push    edi
    push    ebp

    mov     ebx, 1

    mov     ebp, [esp + 20]
    mov     edi, [esp + 24]           ; lpBuffer
    xor     ecx, ecx
    lea     edx, [esp + 28]           ; args
    sub     edi, ebx

.B1:
    add     edi, ebx
    movzx   eax, byte [edi]   ; unroll by 2
    test    eax, eax
    je      .nxtstr

    add     edi, ebx
    movzx   eax, byte [edi]
    test    eax, eax
    jne     .B1

.nxtstr:
    sub     edi, ebx
    mov     esi, [edx + ecx * 4]
.B2:
    add     edi, ebx
    movzx   eax, byte [esi]   ; unroll by 2
    mov     [edi], al
    add     esi, ebx
    test    eax, eax
    jz      .F1

    add     edi, ebx
    movzx   eax, byte [esi]
    mov     [edi], al
    add     esi, ebx
    test    eax, eax
    jne     .B2

.F1:
    add     ecx, ebx
    cmp     ecx, ebp                ; pcount
    jne     .nxtstr

    mov     eax, [esp + 24]           ; lpBuffer

    pop     ebp
    pop     edi
    pop     esi
    pop     ebx
    ret

enter image description here

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.