堆栈和数组在汇编8086中

huangapple go评论81阅读模式
英文:

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, spadd 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
  1. loop指令依赖于CX寄存器。不要忘记在使用之前初始化它。
  2. 由于你将与已知长度为6个字符的固定字符串进行比较,如果输入字符串的长度不是6,则将返回'false'将会更有意义。

endd:
ends
end start
mov ax, 4c00h ; 退出到操作系统。
int 21h
ends
end start

不要重复那些endsend 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
  1. The loop instruction depends on the CX register. Don't forget to initialize it beforehand.
  2. 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

根据你的代码,我可以看到一些逻辑错误。最重要的理解是,在使用 pushpop 时,必须以两个字节为单位访问 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 axalah 在堆栈上的顺序是哪个,如果一个不起作用,请尝试另一个。)

英文:

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 &quot;Wabbit&quot; with db &quot;W&quot;,0,&quot;a&quot;,0,&quot;b&quot;,0,&quot;b&quot;,0,&quot;i&quot;,0,&quot;t&quot;,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 &quot;W&quot;,0,&quot;a&quot;,0,&quot;b&quot;,0,&quot;b&quot;,0,&quot;i&quot;,0,&quot;t&quot;,0 might actually be db 0,&quot;W&quot;,0,&quot;a&quot;,0,&quot;b&quot;,0,&quot;b&quot;,0,&quot;i&quot;,0,&quot;t&quot;, 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.)

huangapple
  • 本文由 发表于 2023年7月20日 19:58:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/76729617.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定