鱼C论坛

 找回密码
 立即注册
查看: 1358|回复: 5

[已解决]汇编语言的一段代码不理解,有很多不懂的地方

[复制链接]
发表于 2023-5-20 19:58:34 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
  1. assume cs:code
  2. data segment                  ;定义数据段(俺也不太懂它的作用,只知道它可以用来定义变量)
  3.      VARM1 dw ’1‘    ;定义变量VARM1
  4.      VARB db 12 dup(0)     ;同上
  5.      VARM dw 16 dup(0)
  6. data ends
  7. code segment                 ;定义代码段
  8. start:mov bl,0                 
  9.       mov ax,VARW1        ;怎么感觉把VARW1当成寄存器了,不理解
  10.           add ax,0              ;0和ax相加不还是ax吗?有啥用
  11.           js done                 ;有符号就跳转,也就是最高位为“1”就跳转,然后done就可以记下左移次数和结果
  12. GOON: INC bl                 ;也就是说,执行完上面的操作之后发现最高位不是“1”就bl自加1?这样不就只加一次吗?万一要移很多次呢?
  13.       add ax,ax               ;左移(为啥?)
  14.           cmp ax,0
  15. done:mov VARM,ax        ;保存左移后的结果
  16.      mov VARB,bl             ;保存左移次数
  17. code ends
  18. end start
复制代码

;将字变量VARM1中的非零数据左移到最高位为“1”止,
;左移次数存入字节变量VARB中,左移后的结果保存入字变量VARM中
我想实现以上功能,但是我对汇编一窍不通,注释是一点点理解,想请问一下我该怎么根据错误来改正呀


                               
登录/注册后可看大图

最佳答案
2023-5-20 19:59:25
这段汇编代码的作用是将变量VARM1中的非零数据左移,直到最高位为1止,同时记录左移次数和左移后的结果。下面是对代码中一些不理解的地方的解释:

1. 数据段用于定义程序中需要用到的变量,包括全局变量和局部变量等。在这段代码中,VARM1、VARB和VARM都是定义的变量。

2. mov ax, VARW1这一行代码的作用是将变量VARW1中的值赋给寄存器ax。可能是笔误,应该是VARM1。

3. add ax, 0这一行代码的作用是将寄存器ax中的值加上0,实际上没有任何作用,可以直接省略。

4. js done这一行代码的作用是判断ax寄存器中的值是否为负数(即最高位为1),如果是负数则跳转到done处执行相应的操作。

5. INC bl这一行代码的作用是将寄存器bl中的值加1,用于记录左移次数。

6. add ax, ax这一行代码的作用是将寄存器ax中的值左移一位,相当于乘以2。

7. 比较指令cmp ax, 0的作用是将寄存器ax中的值与0进行比较,如果相等则跳转到done处执行相应的操作。

总的来说,这段代码的实现思路是将变量VARM1中的值左移,每左移一次就将左移次数加1,直到最高位为1时停止左移,并将左移后的结果保存到变量VARM中。
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2023-5-20 19:59:25 | 显示全部楼层    本楼为最佳答案   
这段汇编代码的作用是将变量VARM1中的非零数据左移,直到最高位为1止,同时记录左移次数和左移后的结果。下面是对代码中一些不理解的地方的解释:

1. 数据段用于定义程序中需要用到的变量,包括全局变量和局部变量等。在这段代码中,VARM1、VARB和VARM都是定义的变量。

2. mov ax, VARW1这一行代码的作用是将变量VARW1中的值赋给寄存器ax。可能是笔误,应该是VARM1。

3. add ax, 0这一行代码的作用是将寄存器ax中的值加上0,实际上没有任何作用,可以直接省略。

4. js done这一行代码的作用是判断ax寄存器中的值是否为负数(即最高位为1),如果是负数则跳转到done处执行相应的操作。

5. INC bl这一行代码的作用是将寄存器bl中的值加1,用于记录左移次数。

6. add ax, ax这一行代码的作用是将寄存器ax中的值左移一位,相当于乘以2。

7. 比较指令cmp ax, 0的作用是将寄存器ax中的值与0进行比较,如果相等则跳转到done处执行相应的操作。

总的来说,这段代码的实现思路是将变量VARM1中的值左移,每左移一次就将左移次数加1,直到最高位为1时停止左移,并将左移后的结果保存到变量VARM中。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-5-20 20:08:45 | 显示全部楼层
isdkz 发表于 2023-5-20 19:59
这段汇编代码的作用是将变量VARM1中的非零数据左移,直到最高位为1止,同时记录左移次数和左移后的结果。下 ...

首先感谢解答,还有不明白的是第5点说到INC bl的作用是bl的值+1,记录左移次数,看代码他只执行了一次,是不是代表bl的值最大就是1?
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-5-20 20:13:31 | 显示全部楼层
倔强青铜铜 发表于 2023-5-20 20:08
首先感谢解答,还有不明白的是第5点说到INC bl的作用是bl的值+1,记录左移次数,看代码他只执行了一次, ...

INC bl 的确只是将 bl 的值增加1,但你需要注意到这一指令在一个循环中。循环开始于 start 标签,并在 GOON 标签的前面结束,条件为当 ax 的最高位为 1 时(即ax为负数时,因为js指令是检测“负数溢出”),它将跳转到 done 标签处。

如果 ax 的最高位不是 1,那么程序就会返回到 GOON,再次执行 INC bl。这个过程会重复,直到 ax 的最高位为 1 为止。因此,INC bl 可能会执行多次,所以 bl 的值可能会大于1,即左移的次数可能会大于1。这也是你提到的“左移到最高位为1”过程的实现方式。

需要注意的是,你的代码里面缺少了循环的跳转部分,你应该在代码中添加 jmp GOON 指令。代码应修改为:

  1. start:mov bl,0                 
  2.       mov ax,VARM1        
  3.       add ax,0              
  4.       js done                 
  5. GOON: INC bl                 
  6.       add ax,ax               
  7.       cmp ax,0
  8.       jns GOON ;添加这行来进行跳转
  9. done:mov VARM,ax        
  10.      mov VARB,bl
复制代码


这样,只有当 ax 的最高位为 1(即ax为负数)时,它才会跳出循环,否则它会不断地返回 GOON,bl 的值会持续增加,代表着左移的次数。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2023-5-20 20:16:08 | 显示全部楼层
isdkz 发表于 2023-5-20 20:13
INC bl 的确只是将 bl 的值增加1,但你需要注意到这一指令在一个循环中。循环开始于 start 标签,并在 GO ...

感谢!
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-5-20 21:18:38 | 显示全部楼层
倔强青铜铜 发表于 2023-5-20 20:08
首先感谢解答,还有不明白的是第5点说到INC bl的作用是bl的值+1,记录左移次数,看代码他只执行了一次, ...


首先,在这段代码中出现了一些错误和问题:

VARW1 这个变量在数据段中没有被定义,应该改为 VARM1。

add ax,0 这行代码没有实际意义,可以直接删去。

js done 这个条件跳转是错误的,应该使用 jns done,表示只有最高位不是 1 的时候才跳转到 done 标签,否则就继续执行下面的代码。

在 GOON 标签后的代码中,应该使用 jl done 条件跳转到 done 标签,因为当左移次数超过 16 次时(即最高位已经移动到了最低位),程序应该结束。

在保存左移结果和左移次数时,应该使用 mov word ptr VARM, ax 和 mov byte ptr VARB, bl,因为 VARM 是一个双字(4 字节)变量,而 ax 寄存器只有 2 字节;而 VARB 是一个字节变量,而 bl 寄存器只有 1 字节,需要使用 byte ptr 显式指定存储数据的大小。

修改后的代码如下:
  1. data segment
  2.     VARM1 dw '1'
  3.     VARB db 12 dup(0)
  4.     VARM dw 16 dup(0)
  5. data ends

  6. code segment
  7. start:
  8.     mov bl, 0
  9.     mov ax, VARM1
  10. check:
  11.     jns done
  12. goon:
  13.     inc bl
  14.     add ax, ax
  15.     cmp bl, 16
  16.     jl done
  17.     jmp check
  18. done:
  19.     mov word ptr VARM, ax
  20.     mov byte ptr VARB, bl
  21.     ; 程序结束
  22. code ends
  23. end start
复制代码

这个程序的主要逻辑是检查 VARM1 中二进制表示中最高位为 1 的位置,然后将其左移至最高位,并记录左移的次数和结果。具体来说,程序首先将 VARM1 的值赋给 ax 寄存器,然后不断将 ax 左移,并使用 bl 记录左移的次数,直到最高位(即符号位)为1。最后,程序将左移后的结果保存在 VARM 变量中,将左移次数保存在 VARB 变量中。


针对你的“还有不明白的是第5点说到INC bl的作用是bl的值+1,记录左移次数,看代码他只执行了一次,是不是代表bl的值最大就是1?”,我的回答是:不是的,INC bl 表示将 bl 中的值加 1,也就是说在 GOON 标签后,每执行一次 INC bl,就意味着左移次数加 1。程序会一直循环执行 GOON 标签后的代码,直到左移次数超过了 16 次(即最高位已经移动到了最低位),或者已经左移至最高位为 1。所以实际上 bl 的值可能会达到 16,并不止是 1。

有用请设置最佳答案
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-4-19 22:28

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表