如何将字符添加到 Assembly 中的 32 位数组?

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

我正在用 Assembly 开发一个简单的 16 位实模式内核,作为 DOS 克隆内核。我目前正在尝试通过获取用户键入的每个字符并将其附加到数组来将用户输入读取为字符串。该函数应该 return 数组(为什么我还没有实现)作为一个字符串。但是,我的以下代码不起作用。为什么?提前致谢。我正在使用 NASM 汇编程序,如果它有所作为的话。

 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

你不能轻易地在汇编中动态增长你的数组,INPUT_STRING: resb 4 保留 4 个字节(最大输入是 3 个字符 + 13 <CR> 个字符)。然后 add al,4 使 al 中的指针前进 4 个字节,即在第一次迭代后完全离开保留内存 (甚至没有提到 al 被 BIOS 修改为return里面的值,实模式下需要16位的寄存器来存放内存地址偏移量,而al只有8位),只能在内存中写入字符地址 INPUT_STRING+0, INPUT_STRING+1, INPUT_STRING+2, INPUT_STRING+3(除非您想覆盖一些您可能不小心将其用于其他用途的内存)。这是如何在 ASM 中实现固定大小 "arrays" 的一般简单原则(如果您愿意,您当然可以使用更复杂的设计,只有您的代码是限制,您对 CPU 和内存所做的事情): 您保留 N*data_type_size 字节,并在偏移量 +0*data_type_size、+1*data_type_size、2*data_type_size 处写入值 ... ASCII 字符每个字符是 1 个字节长,所以 "array" 的元素的偏移量是简单的 0, 1, 2, ...

同样在您的代码中,您必须每次在 int 16h 之前将 AH 重新设置为零,因为中断将使用键盘扫描码修改 AH。如果你有固定大小的输入数组,你应该检查最大输入大小。

一些简单粗暴的例子(正确的命令行输入也应该处理退格等特殊键):

在数据中全局固定大小的缓冲区(256字节)是这样保留的:

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

以及将用户输入存储到其中的代码,检查最大长度输入。

    ...

    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

ret 之后,地址 INPUT_STRING 处的内存将包含带有用户输入的 ASCII 字符的字节。例如,如果用户将点击 Abc123<enter>,地址 INPUT_STRING 处的内存将如下所示(十六进制字节):41 62 63 31 32 33 00 ?? ?? whatever was there before ... ?? ??,六个 ASCII 字符和第七个空终止符(+6偏移量)位置。这对于像 printf 和类似的常见 C 函数来说 "C string" 就足够了(它是相同的内存 structure/logic,因为 C 语言确实使用它 "strings")。