user8735693
user8735693

Reputation:

How do I add chars to an array of 32-bits in Assembly?

I am developing a simple 16-bit Real Mode kernel in Assembly, as a DOS clone kernel. I am currently trying to read user input as a string by taking every character they type, and appending it to an array. The function should return the array (why I have yet to implement) as a string. However, my following code does not work. Why? Thanks in advance. I am using the NASM Assembler, if it makes a difference.

 7 section .bss:
 8     INPUT_STRING: resb 4
 9 section .text:
    ....
 39     scans:
 40         mov ah, 0x00
 41     .repeat:
 42         int 16h
 43         cmp al, 0
 44         je .done
 45         cmp al, 0x0D
 46         ; jump straight to returning the array, implement later
 47         mov [INPUT_STRING+al], 1
 48         add al, 4
 49         jmp .repeat
 50     .done:
 51         ret

Upvotes: 0

Views: 2643

Answers (1)

Ped7g
Ped7g

Reputation: 16606

You can't easily dynamically grow your array in assembly, the INPUT_STRING: resb 4 reserves 4 bytes (max input is then 3 characters + 13 <CR> char). Then add al,4 makes your pointer in al to advance by 4 bytes, i.e. completely off the reserved memory after first iteration (not even mentioning that al is modified by BIOS to return value in it, and that you need 16 bit register to store memory address offset in real mode, while al is only 8 bits), you can write chars only into memory at addresses INPUT_STRING+0, INPUT_STRING+1, INPUT_STRING+2, INPUT_STRING+3 (unless you want to overwrite some memory which you may accidentally use for something else). That's general simple principle how fixed-size "arrays" may be implemented in ASM (you can of course use more complicated design if you wish, only your code is the limit, what you do with your CPU and memory): you reserve N*data_type_size bytes, and write there values at offsets +0*data_type_size, +1*data_type_size, 2*data_type_size ... in case of ASCII characters each character is 1 byte long, so the offsets of elements of "array" are simple 0, 1, 2, ...

Also in your code you have to re-set the AH to zero every time ahead of int 16h, because the interrupt will modify AH with keyboard scancode. And you should check for maximum input size, if you have fixed-size input array.

Some simple very basic and crude example (proper command line input should also handle special keys like backspace, etc):

In the data the global fixed size buffer (256 bytes) is reserved like this:

INPUT_BUFFER_MAX_LEN    equ 255
; reserver 255 bytes for input and +1 byte for nul terminator
INPUT_STRING:   resb    INPUT_BUFFER_MAX_LEN+1

And the code to store user input into it, checking for max length input.

    ...

    scans:
        mov     di,INPUT_STRING                 ; pointer of input buffer
        lea     si,[di+INPUT_BUFFER_MAX_LEN]    ; pointer beyond buffer
    .repeat:
        ; check if input buffer is full
        cmp     di,si
        jae     .done   ; full input buffer, end input
        ; wait for key press from user, using BIOS int 16h,ah=0
        xor     ah,ah   ; ah = 0
        int     0x16
        ; AL = ASCII char or zero for extended key, AH = scancode
        test    al,al
        jz      .done   ; any extended key will end input
        cmp     al,13
        je      .done   ; "Enter" key will end input (not stored in buffer)
        ; store the ASCII character to input buffer
        mov     [di],al ; expects ds = data segment
        inc     di      ; make the pointer to point to next char
        jmp     .repeat ; read more chars
    .done:
        ; store nul-terminator at the end of user input
        mov     [di],byte 0
        ret

After ret the memory at address INPUT_STRING will contain bytes with user inputted ASCII characters. For example if the user will hit Abc123<enter>, the memory at address INPUT_STRING will look like this (bytes in hexadecimal): 41 62 63 31 32 33 00 ?? ?? whatever was there before ... ?? ??, six ASCII characters and the null terminator at seventh (+6 offset) position. This would suffice as "C string" for common C functions like printf and similar (it's same memory structure/logic, as the C language does use for it's "strings").

Upvotes: 0

Related Questions