【问题标题】:How do I add chars to an array of 32-bits in Assembly?如何将字符添加到汇编中的 32 位数组?
【发布时间】:2018-04-19 22:21:41
【问题描述】:

我正在Assembly 中开发一个简单的16 位实模式内核,作为DOS 克隆内核。我目前正在尝试通过获取用户输入的每个字符并将其附加到数组中来将用户输入作为字符串读取。该函数应该将数组(为什么我还没有实现)作为字符串返回。但是,我的以下代码不起作用。为什么?提前致谢。我正在使用 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+al] 不是有效的寻址模式。你确定它应该是al 吗?我希望字符串中有一个索引。
  • 我不确定......汇编中的数组让我有点困惑,但我在我的手册中找不到任何条目。我可能需要看看 TutorialsPoint 什么的。
  • 数组不能真正出现在手册中 - 它们不是处理器功能,实现它们。
  • @harold 所以为了让我自己实现这个,我必须使用该变量,将计数器存储在某个寄存器中,然后循环直到按下 Enter 键。
  • 听起来不错。顺便看看16bit ModRM 选择一个你实际可以这样使用的索引的寄存器。

标签: string assembly nasm bios


【解决方案1】:

你不能轻易地在汇编中动态地增长你的数组,INPUT_STRING: resb 4 保留 4 个字节(最大输入是 3 个字符 + 13 <CR> char)。然后add al,4 使al 中的指针前进4 个字节,即在第一次迭代后完全脱离保留内存(甚至没有提到al 被BIOS 修改为在其中返回值,并且你需要 16 位寄存器来存储实模式下的内存地址偏移量,而 al 只有 8 位),您只能将字符写入内存地址 INPUT_STRING+0, INPUT_STRING+1, INPUT_STRING+2, INPUT_STRING+3(除非您想覆盖一些您可能不小心用于其他用途)。这是如何在 ASM 中实现固定大小的“数组”的一般简单原则(如果您愿意,当然可以使用更复杂的设计,只有您的代码是限制,您对 CPU 和内存的处理方式):您保留 N* data_type_size 字节,并在偏移量处写入值 +0*data_type_size, +1*data_type_size, 2*data_type_size ... 如果是 ASCII 字符,每个字符的长度为 1 字节,因此“数组”元素的偏移量是简单的 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 字符串”(它是相同的内存结构/逻辑,因为 C 语言确实使用它的“字符串”)。

【讨论】:

  • 非常感谢!我被困在这上面太久了!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-20
  • 1970-01-01
  • 2019-03-24
  • 2014-01-09
  • 2020-02-17
  • 1970-01-01
相关资源
最近更新 更多