英文:
Stack and array in assembly 8086
问题
data segment
S db 20 dup('$')
T db 'true$'
F db 'false$'
A db 'Wabbit$'
ends
stack segment
dw 128 dup(0)
pile:
ends
code segment
start:
mov ax, data
mov ds, ax
mov es, ax
mov dx, offset S
mov ah, 10
int 21h
mov cl, S[1]
mov ch, 0
mov dx, offset S
add dx, 2
mov ah, 9
int 21h
mov sp, pile
mov si, 5
mov bp, sp
for1:
mov al, A[si]
mov ah, 0
push ax
dec si
cmp si, 0
jge for1
mov bp, sp
add bp, 12
mov si, 2
for:
sub bp, 2
mov bx, [bp]
mov ax, 0
mov al, S[si]
mov ah, 0
cmp bx, ax
jne exit
inc si
loop for
mov dx, offset T
mov ah, 9
int 21h
jmp endd
exit:
mov dx, offset F
mov ah, 9
int 21h
endd:
ends
end start
mov ax, 4c00h ; exit to the operating system.
int 21h
ends
end start ; set the entry point and stop the assembler.
在你的代码中,有一些问题导致了错误的结果。首先,你在字符串S中使用了HTML实体编码的字符,这会导致混淆。应该使用普通的字符来表示字符串。
其次,你在比较字符串S的字符和栈中的字符时,使用了不正确的方式。8086汇编中,字符串是以ASCII码表示的,所以你需要比较ASCII码而不是字符本身。所以,你需要将 mov al,S[si]
中的 al
更改为 ax
,以便正确地获取字符串S中的字符的ASCII码。
上述更正后的代码应该能够正确比较字符串S和栈中的值,然后显示"true"或"false"。
英文:
data segment
S db 20 dup('$')
T db 'true$'
F db 'false$'
A db 'Wabbit$'
ends
stack segment
dw 128 dup(0)
pile:
ends
code segment
start:
mov ax, data
mov ds, ax
mov es, ax
mov dx,offset S
mov ah,10
int 21h
mov cl,S[1]
mov ch,0
mov dx,offset S
add dx,2
mov ah,9
int 21h
mov sp,pile
mov si, 5
mov bp,sp
for1: mov al,A[si]
mov ah,0
push ax
dec si
cmp si,0
jge for1
mov bp,sp
add bp,12
mov si,2
for:
sub bp,2
mov bx,[bp]
mov ax,0
mov al,S[si]
mov ah,0
cmp bx,ax
jne exit
inc si
loop for
mov dx , offset T
mov ah,9
int 21h
jmp endd
exit:
mov dx,offset F
mov ah,9
int 21h
endd:
ends
end start
mov ax, 4c00h ; exit to operating system.
int 21h
ends
end start ; set entry point and stop the assembler.
That is my code.
This is the question:
> Write an 8086 assembly program that takes from the user a string S of size 20 and determines whether the content of S is found on the top of a given stack of words (2 bytes) already defined and filled with the values shown below:
> Example: let S1="Wabbit" entered by the user and the content of the stack is given above, the program will display "True" and S2="Exam", the program will display "False". Remember the content of stack is fixed always "Wabbit", however the content of S changes.
Also I have 'false', why?
I try to know the problem by running step by step so when I do pop first I have 74h the value of "W" but when I put the value of "W" from the string S it gives 57h. Why?
答案1
得分: 1
S db 20 dup('$')
T db 'true$'
F db 'false$'
S 缓冲区的定义是错误的。它是一个充满了缓冲区溢出和内存损坏的明显漏洞。在这里,第一个字节应该通知 DOS 缓冲区的长度,ASCII 为'$',因此 DOS 可以并且将覆盖(部分)缓冲区内存中的'true'和'false'消息!
正确使用 DOS.BufferedInput 函数 0Ah。详细了解请查看 https://stackoverflow.com/questions/47379024/how-buffered-input-works。
mov dx,offset S
add dx,2
mov ah,9
DOS.PrintString 函数 09h 期望接收一个以$结尾的字符串。你认为通过预先加载缓冲区以$字符来实现这一点。然而,没有任何保证这些$字符在函数0Ah返回后仍然存在。你应该始终显式放置一个$字符。再次阅读 https://stackoverflow.com/questions/47379024/how-buffered-input-works。
mov bp,sp <<< 第一次
for1:
mov al,A[si]
mov ah,0
push ax
dec si
cmp si,0
jge for1
mov bp,sp <<< 第二次
add bp,12 <<< 在BP中的值相同
for1 循环正确将包含文本"Wabbit"的字符串A推送到堆栈上,但为什么要两次设置BP寄存器?你可以简单地省略底部的mov bp, sp
和add bp, 12
行,更好的是也删除顶部的mov bp, sp
行,因为这是程序出现故障的根本原因。
你正在比较两个字符串,但对于输入的字符串,你是从第一个字符开始,而对于堆叠的字符串,你是从最后一个字符开始。起始点需要对应。
而且,因为我看不到先将"Wabbit"字符串推送到堆栈上,然后像在内存中定义的常规字符串一样遍历它的充分理由,我建议你为比较的目的使用pop
字符:
mov dx, offset F
mov cl, S[1] ; 1
mov ch, 0 ; 1
cmp cx, 6 ; 2
jne exit ; 2
mov si, 2 ; 我们在SI和SP中有相同数量的字符
for:
pop ax
cmp al, S[si]
jne exit
inc si
loop for ; 1
mov dx , offset T
exit:
mov ah, 09h
int 21h
mov ax, 4C00h
int 21h
loop
指令依赖于CX寄存器。不要忘记在使用之前初始化它。- 由于你将与已知长度为6个字符的固定字符串进行比较,如果输入字符串的长度不是6,则将返回'false'将会更有意义。
endd:
ends
end start
mov ax, 4c00h ; 退出到操作系统。
int 21h
ends
end start
不要重复那些ends
和end start
行!
英文:
> S db 20 dup('$')
> T db 'true$'
> F db 'false$'
The definition for the S buffer is wrong. It is an open invitation for buffer overflow and memory corruption. The first byte, that should inform DOS about the length of the buffer, is 36 here (ASCII for '$'). So DOS can and will overwrite (parts of) those 'true' and 'false' messages for the buffer memory!
Learn to use the DOS.BufferedInput function 0Ah correctly. Read all about it in https://stackoverflow.com/questions/47379024/how-buffered-input-works.
> mov dx,offset S
> add dx,2
> mov ah,9
The DOS.PrintString function 09h expects to receive a $-terminated string. You think you've done that by pre-loading the buffer with $ characters. There's no guarantee whatsoever that those $ characters are still there once the function 0Ah returned. You should always put a $ character explicitly. Again, read about it in https://stackoverflow.com/questions/47379024/how-buffered-input-works.
> mov bp,sp <<<< first time
> for1:
> mov al,A[si]
> mov ah,0
> push ax
> dec si
> cmp si,0
> jge for1
> mov bp,sp <<<< second time
> add bp,12 <<<< same value in BP
The for1 loop correctly pushes the A string that contains the text "Wabbit" on the stack, but why do you setup the BP register twice? You could simply omit those mov bp, sp
add bp, 12
lines at the bottom, but better also remove the mov bp, sp
line at the top because that's the root cause why the program malfunctions.
You are comparing two strings but starting at the first character for the inputted string and starting at the last character for the stacked string. The starting points need to correspond.
And because I see no good reason to first push
the "Wabbit" string on the stack, only to traverse it like a regular string in memory (such as it was defined at A), I suggest you pop
the characters for the purpose of comparing:
mov dx, offset F
mov cl, S[1] ; 1
mov ch, 0 ; 1
cmp cx, 6 ; 2
jne exit ; 2
mov si, 2 ; We have same number of characters at SI as at SP
for:
pop ax
cmp al, S[si]
jne exit
inc si
loop for ; 1
mov dx , offset T
exit:
mov ah, 09h
int 21h
mov ax, 4C00h
int 21h
- The
loop
instruction depends on the CX register. Don't forget to initialize it beforehand. - And because you will be comparing against a fixed string with a known length of 6 characters, it will make sense to return 'false' if the length of the inputted string is anything other than 6.
> endd:
> ends
> end start
> mov ax, 4c00h ; exit to operating system.
> int 21h
> ends
> end start
You should not duplicate those ends
and end start
lines!
答案2
得分: -2
根据你的代码,我可以看到一些逻辑错误。最重要的理解是,在使用 push
或 pop
时,必须以两个字节为单位访问 x86 的堆栈。没有 push al
,你必须使用 push ax
,例如。你似乎明白这一点,这就是为什么你使用 mov ah,0
作为填充的原因。
然而,最终用户无法将这个填充添加到他们输入的字符串中。因此,即使你在程序开头输入 "Wabbit",你的程序仍然尝试将 db "Wabbit"
与 db "W",0,"a",0,"b",0,"b",0,"i",0,"t",0
进行比较,这就是为什么你得到 "false" 作为答案的原因。为了正确比较这两者,你需要将输入字符串转换为与堆栈上存储的测试字符串 "Wabbit" 类似填充的形式。
(附带说明:我之前给出的示例 db "W",0,"a",0,"b",0,"b",0,"i",0,"t",0
可能实际上是 db 0,"W",0,"a",0,"b",0,"b",0,"i",0,"t"
,我不记得当你 push ax
时 al
和 ah
在堆栈上的顺序是哪个,如果一个不起作用,请尝试另一个。)
英文:
Looking at your code, I can see a few logic errors. The most important thing to understand is that x86's stack must be accessed two bytes at a time when using push
or pop
. There is no push al
, you have to use push ax
, for example. You seem to understand that, which is why you have used mov ah,0
as padding.
However, the end user isn't able to put this padding into the string they type. So even if you type "Wabbit" at the beginning of the program, your program is trying to compare db "Wabbit"
with db "W",0,"a",0,"b",0,"b",0,"i",0,"t",0
which is why you're getting "false" as the answer. In order to properly compare the two you'd need to convert the input string to a similar padded form that your test string "Wabbit" is stored on the stack.
(Side note: The example I gave earlier db "W",0,"a",0,"b",0,"b",0,"i",0,"t",0
might actually be db 0,"W",0,"a",0,"b",0,"b",0,"i",0,"t"
, I can't remember off the top of my head which order al
and ah
go on the stack when you push ax
. If one doesn't work try the other.)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论