汇编语言学习记录

有关于学习汇编语言过程中遇到的各种问题与思考(持续更新)

第一次作业

做第一次作业的时候也就上手的时候稍微困难一些,掌握了语言逻辑之后基本都挺顺畅的,但是寄存器的使用还是比较生疏,只能凭感觉瞎选。老师的主页上传了一个简化版本的源文件(输入字符串后输出),我的代码也是在这个基础上修改而来的。编辑汇编程序使用editplus,新建asm文件直接开编就行,写完程序之后,可以把这个文件保存在masm目录下面,打开命令行找到masm文件

我的是输入D:找到D盘,再输入cd \masm找到masm文件,然后输入masm hello;(其中hello是asm文件的文件名,并且这里和后面的link都要注意加封号,不然会弹出几个问题要按几次回车才能继续),会进行编译,输入link hello;生成exe文件,然后直接输入hello,就可以运行这个exe文件了。

关于第一次作业犯过的那些错

  1. 用masm32编译会导致开头报错(指mov as, data,所以必须要用masm,并且把asm文件放在masm目录里面
  2. 一开始编译是点开exe文件运行的,但这时候输出部分就会瞬间显示完瞬间关闭窗口,逼得我只能录像一帧一帧找程序的输出,后来用命令行运行就可以直接得到能够一直显示的结果。
  3. 引用寄存器错误,cx是16位寄存器,我在用寄存器提取数组元素的时候用了cx导致占用位数过长,一直没办法输出正常的东西,抠了一晚上的头发检查了无数遍代码最后才考虑到这个问题。。把cx改成cl(八位寄存器)就立竿见影程序正常了

由于诚信守则,我就不在这里上传我(蹩脚的)源代码了,想要可以直接跟我说。。。

第二次作业

(本次作业提供C语言源代码)

果然单看题目就不是很有做的欲望呢 //在交作业的前夜紧急写完作业的我又来了

老规矩的想要我的蹩脚源代码和学习资料()直接找我。。以及这次也遇到了一些问题

  1. 关于显示的行列控制,命令行窗口的大小是160*25,但是在换行时(x,y)偏移地址的定位并不是直接bx=(80*y+x)*2,好像还要稍微试一下,我是在上一个数据占用了几个byte的基础上算的,每换一行,偏移地址要加9Ch,每列占用空间是14byte(7个字符),所以在输出了三个字符的基础上偏移地址是加上08h再继续输出下一组数据
  2. 还是寄存器的问题。。我的室友说他们的助教强调了不能把寄存器当作变量来使用,要习惯于只使用4个及以内的寄存器数量。但是我还做不到,一开始我试图把16位寄存器的高八位和低八位分开来当作两个变量使用(就是把bl和bh分开来储存两个完全无关的值),但是这样好像时会出现一定问题的,编译的时候会出现warning,并且最后debug的时候确实验证了是寄存器这样使用导致我的输出有问题。最后我把本来使用的bh改成没有使用过的dx问题才得到解决。ax、bx、cx、dx都是16位寄存器,si、di储存偏移地址比较多,ax感觉比较多用在调用中断上面,基本也不太能用。
  3. 关于rol循环左移,这里用到了rol al,4 直接masm编译是会报错的,但是写四遍rol al,1不会报错,这时候在程序最开始segment前面加上.386,并且在每个segment后面加上use16,表示我们的电脑是可以十六进制计算的,就可以通过编译了。
  4. 这次作业用到的输出方式不是int21h里面的,而是直接定位图形界面的那种,最前面mov ax,0B800h再mov es,ax定位到对应地址,然后可以用mov byte ptr es:[di],ax来直接输出了,这里di是偏移地址,al保存要输出的字符,ah保存输出字符的颜色,ah第一位是背景色,第二位是前景色。
  5. 为达到清屏效果可以调用int10h,不清屏的话再加上一开始测试数据比较乱真的很掉san。。代码为:mov ax,03h int 10h
不清屏的效果
输出2000个A
关于图形

才刚快乐了一个星期第三次作业就出现了。。。真的裂开

第三次作业

根据我的尿性我很可能会在ddl截止前两天才做这个作业。。。并且那段时间连续有两篇重要的课程论文截止,大概又会是一段痛苦的日子吧

很好 我果然度过了一段痛苦的日子。。。在ddl截止前2天我开始做了而且几乎花费了我的所有课余时间,但是一直有一个bug无法改好,因此最后上交的是半成品。12月17日我下定决心痛改前非换了一个算法写,仅仅花了3小时就全部通过了。。现在就是一个后悔

  1. 原本我采用的算法是分别读入每个数,转化之后存入一个数组,把运算符号存在另一个数组内,但是这样就会发现引用时出了问题,当一个数组存了多个数时,若想要mov ax, 位于数组中间的任意一个数,反正只要不是最后一个,它都会把后面的全部数据都算进来,继而在转换时没有办法得到正确的结果。单独测试每部分内容都没有问题
  2. 后来我用了另一种思路,即边转换边计算,这样就可以避免数组存放与取出的问题,不过在这里还需要用到堆栈,这个我不是很熟练,当有多个不同用处的数据存放在堆栈时我可能会乱掉,并且即使使用这部分没有用到过的寄存器也存在一个问题(保存的时候是正常的,但是在运算一圈后到达要用到这个数据的位置时,它突然就变成0了,,但是这部分并没有使用到这个寄存器),所以我另建了一个数组t,把另一个我要全程存放的数据存在t[0]中,算是一种取巧的方法。
  3. 关于输入函数的算法,我直接使用了第一次输入的算法部分,把读入的字符存到数组s里,每转换出一个32位数做一次计算,但实际上据说边读入边转换和计算要更简单一点
  4. 关于输出函数,十进制输出就是逆向一下输入部分,除以10后把余数依次压入堆栈,最后统一输出,十六进制输出可以四位四位转换,用左移四位之后和0Fh求与的方式逐一转换,总体上不是很难
  5. 另外需要注意一下32位的寄存器是eax,ebx,ecx,edx,以及mul和div这两个函数在32位下的使用方式是不一样的。

第四次作业其实在第三次作业截止之前就布置了,但是我太懒惰了在做出那次作业之前坚决不上线0 0。。并且第四次作业复杂度几何级增长,据我室友说她当时写了1k+行,而我前面三次作业没有一次超过200行。。。总之就是非常害怕

第四次作业

相当于当了一个人肉编译器。。。我觉得我很可能无法在规定的截止日期之前完成(别的课程的大作业还没写,并且这该死的拖延症。。)

这一次作业因为与另一门五学分主修课程的大作业撞车,并且期末考提前两天并没有做完。(事实上是在另一门课的大作业通宵干完之后在期末考期间花了三个晚上写的)但是总体难度并没有很高,主要在复杂度上,中间也基本上只需要翻译老师逆向出来的c语句即可

这里感觉主要需要注意的点就是函数的传递以及堆栈的使用

我个人习惯用堆栈段来传递函数的参数,在引用函数之前把需要的参数压入堆栈段中(需要注意一下传入参数的位数,后面会需要计算一下),然后用bp保存当前sp的值,就可以通过bp减一个数的形式来得到之前所保存参数的偏移地址

(我的代码中找出来的)某个函数的参数位置说明

因为在call某个函数的时候,系统会自动往堆栈中压入两个字节,所以在计算的时候要从-2开始去算。

举一个ascii字符转化为16进制输出形式的简单函数为例

char2hex

这里可以看到函数都是先push一大段再全部pop结束的,这样子就可以不影响到本来寄存器中储存的数值。在函数内部需要用到一些会影响特定寄存器的指令(比如mul,要求被乘数保存在ax中,乘数保存在bx中,得出的结果保存在ax中)时,也可以用这种方式来防止干扰。

一个稍微复杂一点的乘法过程,注意从push开始到pop结束

在使用堆栈时,可以按照自己的要求在前面push的时候预留一定空间,在函数中就可以把参数保存到自己预留的空间中

关于第四次作业,我可以提供我自己写的(只差一个main函数,其余基本写完了,但是逻辑还要小修一下,没有实际跑过)和我室友的可以正常运行的全部代码。

期末考试内容和读写代码的能力关系不大,主要是考察指令集的背诵。。会出一些不太常用的指令集和标识符(IF、SF之类的),我当时还在没日没夜的干第四次大作业,然后期末就没怎么复习,期末考考的非常之烂。。。但是不可否认真的学到了挺多的,而且对底层的理解比原来深刻了很多。这门课就当献祭给老师了吧T T

相关书籍可以参考白洪欢写的汇编语言的那本书(现在已经不出版了,我有老师之前给我们打印的版本),也可以参考清华大学出版社的那本《汇编语言》,写的很好,质量堪比外国教材。后续汇编相关的学习大概就是老师的《软件保护技术》了,主页上有很多内容,实在不行问我室友(我室友真的选课一个比一个敢。。软保这种挂科率有50%的课,他们班七八十人选满的课到期末一共只剩了二十多个人,我两个室友都跟到了最后。。)

留下评论

您的电子邮箱地址不会被公开。 必填项已用*标注