我在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
答案 0 :(得分:1)
您无法轻松地在程序集中动态增长数组,INPUT_STRING: resb 4
保留4个字节(最大输入则为3个字符+ 13 <CR>
个字符)。然后add al,4
使你的指针在al
前进4个字节,即在第一次迭代后完全脱离保留的内存(甚至没有提到BIOS修改了al
以返回值在其中,并且您需要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,......
同样在您的代码中,您必须每次AH
之前将int 16h
重置为零,因为中断将使用键盘扫描码修改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)抵消)的位置。对于常见的C函数(如printf
和类似函数)来说,这就足够了(C字符串)(它的内存结构/逻辑与C语言用于“字符串”相同)。