《汇编语言》学习笔记

序:《Orange‘s一个操作系统的实现》的学习笔记已经好久都没写了,不是我放弃了而是我看不懂了,可能是基础实在是太差了,所以我开始学习王爽的《汇编语言》,我准备先为《Oranges》打个基础,我相信,这个我一定能看下去,如果不能,我想我可以放弃这条路了。。。以下内容仅仅是学习过程中的一些琐碎知识的摘抄,和一些个人理解,希望有兴趣的朋友一起讨论!

2012年12月31日

家里网速不给力,一个masm下载了好久,今天终于下载下来了。

我用的是Bochs虚拟机环境,是前面学写《Oranges》弄的dos系统,刚好可以用来学习汇编语言,下载下来的masm和link用虚拟软盘拷贝到dos,感觉特别麻烦,不知道Bochs是否可以关联到本地路径让我可以不用这么麻烦拷来拷去的,哪位大侠要是知道,来指点一下下!!折腾这么长时间,其实自己貌似没做什么。

dos启动后,完成初始化,然后运行command.com程序,这个就是dos下的shell。在执行一个可执行程序的时候,由command程序将准备执行的程序调如内存,并设置cs:ip指向程序的入口。

psp(程序段的前缀)的起始段地址SA,256(100H)个字节,地址范围是SA:0   ~  SA+10H:0(注意段地址需要左移4位)

在实验三中出现一个问题,执行第一句 mov ax,2000h,ax没有改变,但是执行最后一句mov ax,4c00h时,ax就被改变了,为什么?怎么好像是内存越界造成的。

2013年1月2日

loop指令格式:loop 标号

cpu执行loop时,要进行两步操作(1)cx = cx - 1(2)判断cx不为0则跳转至标号处执行

之前没有注意,前面出现的问题很严重啊,导致我程序都没办法正确运行。

2013年1月13日

前两天玩的太high,没学习啊。

虽然程序运行有些问题,但是原因还没找到,继续向下学习

今天看到一个错误  must be index or base register 百度一下得到的结果是

16位汇编不能使用ax间址寻址,只有BX、BP、SI、DI才可以。32位程序才可以用任意32位寄存器间址寻址。
这是我前面学习过程中所忽略掉的  为什么是loop和[bx]一起使用,而不是和[ax],[dx]。因为不用bx会报错!

在第五章实验4的最后一个问那段代码中,我编译都有错误???
p10.asm(3): error A2008: syntax error : ,
p10.asm(8): error A2008: syntax error : ,
p10.asm(12): error A2006: undefined symbol : s
这是为什么呢?哪位大仙能给我解答一下下?
2013年1月14日
今天在学第六章,实验五前两个实验没有出现错误代码的情况,但是做到第三个小实验的时候出现了之前出现过的,代码运行错误的情况
C:\MASM>debug ex5_3.exe
=u
1AD1:0000 B8D51A MOV AX,1AD5
1AD1:0003 8ED0 MOV SS,AX
1AD1:0005 BC1000 MOV SP,0010
1AD1:0008 B8D41A MOV AX,1AD4
1AD1:000B 8ED8 MOV DS,AX
1AD1:000D FF360000 PUSH WORD PTR [0000]
1AD1:0011 FF360200 PUSH WORD PTR [0002]
1AD1:0015 8F060200 POP WORD PTR [0002]
1AD1:0019 8F060000 POP WORD PTR [0000]
1AD1:001D B8004C MOV AX,4C00
=t
AX=D5B8 BX=0000 CX=0244 DX=0000 SP=0002 BP=0000 SI=0000 DI=0000
DS=1AC1 ES=1AC1 SS=1AD1 CS=1AD1 IP=0002 NV UP DI NG NZ NA PE NC
1AD1:0002 1A8ED0BC SBB CL,[BP+BCD0] SS:BCD0=18
 

第三个小实验是把代码段放到最上面,数据段放到了下面,这就导致程序错误,什么原因呢?

之前猜测是越界的问题,执行完第一条的时候ip应该指向3,为什么是2呢?

下面是第二个小实验运行的情况

C:\MASM>debug ex5_2.exe
=r
AX=0123 BX=0000 CX=0242 DX=0000 SP=0002 BP=0000 SI=0000 DI=0000
DS=1AC1 ES=1AC1 SS=1AD1 CS=1AD3 IP=0000 NV UP DI PL NZ NA PO NC
1AD3:0000 B8D21A MOV AX,1AD2
=t
AX=1AD2 BX=0000 CX=0242 DX=0000 SP=0002 BP=0000 SI=0000 DI=0000
DS=1AC1 ES=1AC1 SS=1AD1 CS=1AD3 IP=0003 NV UP DI PL NZ NA PO NC
1AD3:0003 8ED0 MOV SS,AX
1AD3:0005 BC1000 MOV SP,0010
=t
AX=1AD2 BX=0000 CX=0242 DX=0000 SP=0010 BP=0000 SI=0000 DI=0000
DS=1AC1 ES=1AC1 SS=1AD2 CS=1AD3 IP=0008 NV UP DI PL NZ NA PO NC
1AD3:0008 B8D11A MOV AX,1AD1

困惑啊~~~~

push ax可以push al不可以


2013年1月16日

应该是编译器版本的问题

mov al,[bx+si+3]是正确的

mov al,[bx+3+si]是错误的


[...]只可以用bx、si、di、bp、idata的组合

其中在使用bp的时候,没有显性的给出段地址,段地址默认在ss中

mov ax,[bp] 表示 (ax)=((ss)*16+(bp))


inc word ptr [bx]bx作为一个字指针,所指向内容+1

inc byte ptr [bx] bx作为一个字节指针,所指向内容+1

push 和 pop指令只进行字操作


[di+si]是错误操作,[bx+si/di],[bp+si/di],可以

ex7.asm(57): error A2023: instruction operand must have size内存单元和内存单元之间不能赋值运算

2013年1月17日

offset的功能是取得标号的偏移地址,从哪开始的偏移地址


位移 = 标号处地址 - jmp指令后的第一个字节地址

所有有条件转移的指令都是短指令 ,所有循环指令都是短指令

短指令中都是位移

jcxz 标号 当cx=0时,跳转到标号处

loop一定要注意先cx=cx-1,再判断cx是否为0


2013年1月18日

在子程序中所有子程序用到的寄存器内容都保存起来,返回前再恢复

(1)今天在写实验10第3小问的时候,把前面的两个子程序都用上

开始现实66621,应该现实12666

我就在程序里用堆栈令现实内容逆序,结果程序不停的崩溃

后来发现在变成12666字符时,最后一位没有设置0,在填上0后,程序不崩溃了,但是变成了死循环

后来发现有个中间变量bx在子程序调用过程中为没有出时候为0,所以程序进入了死循环

(2)程序在正常运行的时候,也就是不用debug调试的时候,代码初始部分不会被0302H代替,能够正常运行

2013年1月19日

今天做了一下书上的课程设计1,把前面的程序拼一下,还算顺利,心情激动

2013年1月21日

pushf 将将标志寄存器的值压栈 popf将栈中数据弹出到标志寄存器中

zf:判断运算结果是否为0,是为1,不是为0

pf:奇偶标志位  1的个数是偶数为1,1的个数是奇数为0,对于运算指令有效

sf:符号标志位  指令执行结果为负则该位为1,指令执行结果为正则该位为0,无论运算的操作数是有符号还是无符号的,运算的过程都会影响sf,只是看编程者是否需要这位

cf:进位/借位标志位  对无符号数有意义

of:溢出标志位  记录有符号数运算结果是否发生了溢出

df:方向标志位,di、si递增则为0,递减则为1    cld 将df设置为0  std将df设置为1

movsb 相当于 mov es:[di] , byte ptr ds:[si](这个指令不存在)if(DF == 0) inc si inc di    else if (DF==1)dec si dec di

movsw 功能和movsb类似,传送一个字

rep movsb   相当于

s:movsb

 loop s

inc 和 loop指令不影响cf,必要的时候可以用inc代替add

cmp指令中,两个无符号数的判断可以由cf、zf来决定

在有符号数中的判断,先要看of是否溢出,若没溢出sf结果是正确的,若溢出sf结果取反,zf表示相等

本来以为 cmp byte ptr [si],'a'这样的指令不可以,试了一下是可以的

中断子程序返回应该用指令iret,但在在实验12中,中断子程序结束后必须用 mov ax,4c00h   int 21h这两条指令,为什么呢?如果用iret就是死循环

2013年1月22日

iret执行的过程如下

pop ip

pop cs

popf

2013年1月23日

对0~255

in al,20h;从20h端口读入一个字节

out 20h,al;往20h端口写一个字节

对255~65535的端口进行读写时,端口号放在dx中(这是必须的吗)

mov dx,3f80h  ;将端口号3f80h送入dx

in al,dx

out dx,al


shl、shr 如果移动位数大于1位,必须将移动位数放在cl中


时间在CMOS RAM中的存放单元

秒:0       分:2        时:4        日:7       月:8        年:9


2013年1月24日

在后面加有“:”的地址标号,只能在代码段中使用,不能在其他段中使用

如果想在代码段中,用数据段中的数据标号访问数据,则需要中伪指令assume将标号所在的段和一个段寄存器联系起来,否则无法确定标号的段地址在哪一个段寄存器

seg 操作符,功能为取得某一标号的段地址

程序里什么时候应该用偏移,什么时候用段里地址不懂


2013年2月1日

其实上网就为了打一下卡,怕自己坚持不下去

还有最后两个实验和一个课程设计

每次都虎头蛇尾



2013年2月19日

今天终于明白org 7c00h是什么意思,以前在写单片机程序的时候开始总会写一句org 0000h,删掉也没什么,虽然片面的理解是告诉编译器程序是在哪段内存运行的,但是不明白这样运行的意义何在,因为在arm中把某段程序下载到flash中后,由bootloader将其拷贝到特定内存中,cpu由这个特定内存开始执行程序,但是编译器是知道这段内存放在什么位置,所以这段程序的地址是由编译器来计算的,但是在汇编中如果没有org xxxxh这样的语句,编译器是不知道程序员准备将程序放到什么位置,dos下运行程序的时候会将程序的起始位置作为一个段的开头,即ip=0,所以开头的org显的不那么重要,在弄本书课程设计的最后,有一个问题让我很苦恼,

mov si,str0[bx]

这一句单看寄存器,和内存数据都没有问题,但是执行完后si的数据却是非常夸张的,这句的代码反复产看了N遍,终于发现原来程序中的偏移量(如:str0)都是针对程序开始的,而程序的段cs是0,所取得的数据当然很夸张!因为开始有下面的语句

 20     mov ax,cs
 21     mov ds,ax
接下来我把20那句改成

 20     mov ax,codesg

这是程序段的名称,想要做引导的那段程序紧接着段开始,在引导调试的时候这个值是0x15dd,想不通是哪来的值,用debug调试的时候这个值变成了程序运行的cs地址,由于不知道在masm编译器下org 7c00h怎么写,所以我强制将其变为

 20     mov ax,7c00h

重新查看发现没用,而且这几次修改值都一样,这怎么会呢?后来发现反汇编的语句是这样的

mov si, word ptr cs:[bx+116]

运行的段地址是cs,跟我刚才改来改去的ds完全没意义,这是什么原因?

我原句是这么写的

5 codesg segment
  6 code:
  7     jmp code_start
  8 stack:    db 64 dup(0)
  9 str1    db "1) reset pc",0
 10 str2    db "2) start system",0
 11 str3    db "3) clock",0
 12 str4    db "4) set clock",0
 13 str0  dw str1,str2,str3,str4

 25     mov si,str0[bx]

因为st0是在code这个段内,我现在有两种方法,一种是ds:这种方法,另一种是将上面的数据分离到另一个segment中(放在code的原因是因为开始的时候在copy程序的下面)

第一种方法后反汇编结果是这样的

mov si, word ptr ds:[bx+116]

但是查看数据还是不对

回想起来,上面ds段地址是这个值,不对是一定的

 20     mov ax,7c00h

应该把上面的语句改成

20     mov ax,7c0h

引导成功!

由于这只是引导程序,有固定的大小用多个segment貌似不是好方法,而且我也没能实现

虽然觉得这样写并不是什么好方法,但是现在就先这样吧,这只是刚刚开始,这才是引导,功能还没有实现,貌似需要精确计算



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值