LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 986|回复: 12

关于一条汇编程序的困惑,已经好认真看的啦

[复制链接]
发表于 2004-5-18 18:51:28 | 显示全部楼层 |阅读模式
在ADDR单元中存放着数Y的地址,试编制一程序把Y中1的个数存入COUNT单元中
书本的例子
DATAREA SEGMENT
NUMBER DW Y
ADDR DW NUMBER
COUNT DW ?
DATAREA SEGMENT
;
PROGNAM SEGMENT
;
MAIN PROC FAR
ASSUME CSROGNAM,DSATAREA
START:
PUSH DS
SUB AX,AX //AX清零
PUSH AX
MOV AX, DATAREA //AX积寄存了DATAREA的段首地址
MOV DS, AX //再将AX付给DS
MOV CX,0
MOV BX,ADDR //将ADDR的内容传送给BX,也就是BX拿了Y的地址
MOV AX,[BX] //以Y的地址作为偏移地址找到Y的内容并传给AX
REPEAT: TEST AX,0FFFFH
JZ EXIT // Z==0,是指什么结果为0呢?
JNS SHIFT //符号位为0转移
INC CX
SHIFT : SHL AX,1
JMP REPEAT
EXIT: MOV COUNT,CX
RET
MAIN ENDP
PROGNAM ENDS
END START
问题1:我的解析正确吗?
2:NUMBER DW Y
ADDR DW NUMBER
既然最终都是将 Y传给ADDR,为什么不直接只写成一句
ADDR DW Y
3:PUSH DS ,DS为什么要压栈?
4:PUSH AX ,AX为什么又要压栈?对后面有什么有吗?
5:DSATAREA 这一句不是已经将DATAREA的首地址给DS了吗?
怎么要来两句实现相同功能的呢?
MOV AX, DATAREA
MOV DS, AX
6: TEST AX,0FFFFH 这句是什么意思?
发表于 2004-5-18 19:17:32 | 显示全部楼层
问题1:我的解析正确吗
一般般

2:NUMBER DW Y
ADDR DW NUMBER
既然最终都是将 Y传给ADDR,为什么不直接只写成一句
ADDR DW Y
奇怪

3:PUSH DS ,DS为什么要压栈?
为了保存原有的DS,不过好像没必要,除非是作中断服务程序

4:PUSH AX ,AX为什么又要压栈?对后面有什么有吗?
估计这句应该在SUB AX,AX之前吧,为了保存AX原有的数据,同上

5:DSATAREA 这一句不是已经将DATAREA的首地址给DS了吗?
怎么要来两句实现相同功能的呢?
MOV AX, DATAREA
MOV DS, AX
DS必须显式赋值

6: TEST AX,0FFFFH 这句是什么意思?

TEST与AND(与操作)等价,不过它不改变目的操作数AX的值,这点对于本程序的功能而言,值得注意

AX(保存了Y的值)与0FFFFH(全1)进行与操作,测试结果是否为全0,若不为0,说明Y至少有一个1;否则结束循环。
若CY(移出来的位)为1,则CX计数器加1,否则直接进行下一次移位;
如此循环,最终AX为全0,CX的值为Y中1的个数
发表于 2004-5-18 20:13:48 | 显示全部楼层
REPEAT: TEST AX,0FFFFH
JZ EXIT
JNS SHIFT
INC CX                    //似乎这个inc被闲置了
SHIFT : SHL AX,1
JMP REPEAT
发表于 2004-5-18 20:15:57 | 显示全部楼层
何来闲置?请看我上面的分析。

CX保存了Y中1的个数,在移出位CY为1(JNS)时自增。
发表于 2004-5-18 20:28:23 | 显示全部楼层
jz跳到exit去了
jnz跳到shift去了
shift后面的jmp又跳到repeat去了

好像正好把inc隔开了
发表于 2004-5-18 20:48:11 | 显示全部楼层
最初由 luoyong 发表
jz跳到exit去了
jnz跳到shift去了
shift后面的jmp又跳到repeat去了

好像正好把inc隔开了

晕~~~~~建议兄弟好好温习一下汇编语言。

  1. MOV AX,[BX]                ;赋值AX为Y
  2. REPEAT: TEST AX,0FFFFH        ;[color=green]循环R[/color],至AX为全零时结束循环
  3. JZ EXIT                        ;AX与0FFFFH相与,结果若非全零,说明Y至少有一个1,若为全零,说明Y不含1或者移位结束,跳转到EXIT
  4. JNS SHIFT                           ;判断CY(保存了移出的位,初始值为0)是否为1,[color=red]若为1,则继续下一条指令,即CX++;若为0,则跳转到SHIFT,直接移位[/color]
  5. INC CX                        ;CX自增
  6. SHIFT : SHL AX,1                ;移位
  7. JMP REPEAT                           ;跳转到[color=green]循环R[/color]开头
  8. EXIT: MOV COUNT,CX                   ;赋值COUNT为CX,即Y中1的总个数
复制代码
发表于 2004-5-18 20:55:51 | 显示全部楼层
晕~~~~~~

jns看成jnz了

我眼都花了,我想应该休息一下了
发表于 2004-5-18 21:04:34 | 显示全部楼层
建议还是看看Linux的AT&T汇编,直接使用Linux的内核调用或者调用GLIBC库,这样才是现代的汇编学习

ps:其实任何语言本身并不重要,关键是算法的理解。
发表于 2004-6-11 18:15:22 | 显示全部楼层

回复: 关于一条汇编程序的困惑,已经好认真看的啦


PROGNAM SEGMENT
;
MAIN PROC FAR
ASSUME CSROGNAM,DSATAREA
START:
PUSH DS
SUB AX,AX //AX清零
PUSH AX


最近在复习《微机原理》,再谈谈这段代码的含义。
这种写法涉及到DOS程序的惯例。

DOS为每个程序在内存中分配一个PSP段,包含了DOS操作系统的信息,随后紧跟代码段,数据段,堆栈段;其中,为了使程序退出后能返回到DOS的控制下,PSP段的首句为INT 20H(可见,偏移地址为0,这点下面会有所体现)。

DOS初始化程序时,设置DS为PSP段的地址(这也是我们要手动初始化DS为实际数据段的缘故),那么,我们编写的程序代码中就应该要考虑到如何在程序退出时执行这个中断。

历史惯例之一是,设置程序段的距离属性为FAR,程序开头压入DS,清零并压入AX,当ret返回时,由于FAR的缘故,会先把AX弹出到IP,DS弹出到CS,然后执行CS:IP(DS:IP),这样在程序退出时就自动执行INT 20H

当然,还有一个惯例,实现同样的功能,大家很熟悉的。

  1. MOV AX,04CH
  2. INT 21H
复制代码

ps:这个年代希望教育部门update一下,使用AT&T+*nix汇编吧。:-)
发表于 2004-6-11 18:57:40 | 显示全部楼层
我觉得在linux下学习AT&T格式的汇编反而简单。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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