汇编程序语言设计 第一周
学习记录和个人理解,非笔记,有误区,慎看!~
老狗转行系列之汇编:
本职烧锅炉,现转AI系列,基础薄弱,目前正在学习基础,有兴趣的一起来~
第一周
1.硬件组成
1.1 寄存器
重点:硬件分为三个部分:寄存器,输入输出地址,储存器地址
这节课重要的知识点IA32有8个重要寄存器,重点记忆下面一图。
32位寄存器之间到底有什么区别,是不是可以混用等???EAX、EBX、ECX、EDX、ESI、EDI、ESP、EBP 寄存器详解每个汉字我都懂,连在一起蒙圈系列
推荐王爽《汇编语言》
(转)
在用途方面,他们有各自默认的用途:
Eax用来保存所有API函数的返回值。
寄存器AX和AL通常称为累加器(Accumulator),用累加器进行的操作可能需要更少时间。累加器可用于乘、除、输入/输出等操作,它们的使用频率很高;
寄存器BX称为基地址寄存器(Base Register)。它可作为存储器指针来使用;
寄存器CX称为计数寄存器(Count Register)。在循环和字符串操作时,要用它来控制循环次数;在位操作中,当移多位时,要用CL来指明移位的位数;
寄存器DX称为数据寄存器(Data Register)。在进行乘、除运算时,它可作为默认的操作数参与运算,也可用于存放I/O的端口地址。
由于存储的数据大小关系,AX、BX、CX和DX不能作为基址和变址寄存器来存放存储单元的地址, 32位寄存器EAX、EBX、ECX和EDX不仅可传送数据、暂存数据保存算术逻辑运算结果,而且也可作为指针寄存器,所以,这些32位寄存器更具有通用性。(什么是基址,什么是变址以后会说到)
1.2 处理器专用寄存器
专用寄存器有三类:
第一类 标志
改变EIP是可以改变程序的顺序
存储空间是可以分段管理的
1.3 存储器
计算机被分为三个部分,CPU 存储器 IO。存储器对应存储器地址
8位形成字节,16位形成字,32位形成双字,一个存储单位存放的是一个字节,称字节编址。32位可以表征2的32次的名字。32位处理器最多一次处理32位,EAX是32位的
4个二进制,相当于1个16位,32位二进制相当于8个16进制位。H表示16位进制。
MMU存储管理单元。如果程序直接寻找存储器地址是会给存储管理带来麻烦,所以有MMU。
后续学习最多的是平展存储模型。
物理地址与逻辑地址
32位存储空间的划分,可以分为以上部分。
2.程序格式
2.1 处理器指令格式
小结:
指令由操作码和操作数(地址码)组成,左右注意。
这条指令有点像高级语言中的赋值
机器代码也叫指令格式,按照习惯使用16位表示
里面的8B是操作码,操作数部分(Mod R/M)是第二列,SIB也是一种寻址的方式,后面的四个字节都是位移量(80 00 00 00)。上面的格式可能很难理解,但是我们要知道我们高级语言都需要转换成这种机器代码。然后机器代码也不同,同一指令不容数据内容也可能不同。
2.2 语句格式
标号与名字都是用户自己定义的。
定义一个字符
eax也是寄存器,offset msg是操作数
执行性语句,有点像高级语言中的操作。
说明性语句,有点像高级语言的赋值定义等
2.3 源程序框架
stdcall 是标准调用规范
PS:“END”伪指令仅说明汇编到此结束,并不具备返回操作系统的功能。
2.3 信息显示程序
第一个汇编语言程序
13,10对应是\n,在底层内部都是有0 结尾的,字符串结尾字符。这里面Dismsg 相当于Printf()。通过OFFset指出偏移地址。EAX是寄存器,他是进行显示的一个入口参数存放的地方。
程序在IO32.lib 其说明是IO32.inc
注意子程序调用规范
库是前人设计的规范
问题:汇编中定义字符的时候有段基地址什么?
3.开发过程
3.1 MASM开发软件
最主要的是什么系统平台:WINDOWS
汇编程序是将我们源代码转成机器代码的程序。
3.2 操作系统平台
常称为DOS窗口,但是实际上不是
这两者本质有不同
3.3 源程序开发
汇编只是生成一个目标模板文件,然后需要连接称为可执行文件。
不能双击是因为我们生成的控制台,双击并不能看到信息
调试程序:
所谓快速开发,MAKE32就是将步骤汇合在一起
4.程序
1.标准的Hello world
include io32.inc
.data
;数据定义
msg byte 'Hello ,World!',13,10,0
;msgzn byte '你好,瓜娃子!',13,10,0
.code
start:
;主程序
mov eax,offset msg ;显示 这边为什么eax 为什么使用offset
;mov ebx,offset msg
;mov ecx,offset msg
;mov eax,msg
call dispmsg
exit 0
;子程序
end start
2.测试中文可以否
include io32.inc
.data
;数据定义
;msg byte 'Hello ,World!',13,10,0
msg byte '你好,瓜娃子!',13,10,0
.code
start:
;主程序
mov eax,offset msg ;显示 这边为什么eax 为什么使用offset
;mov ebx,offset msg
;mov ecx,offset msg
;mov eax,msg
call dispmsg
exit 0
;子程序
end start
3.测试不用msg1 其他字符
include io32.inc
.data
;数据定义
xjbx byte 'Hello ,World!',13,10,0
;msg byte '你好,瓜娃子!',13,10,0
.code
start:
;主程序
mov eax,offset xjbx ;显示 这边为什么eax 为什么使用offset
;mov ebx,offset msg
;mov ecx,offset msg
;mov eax,msg
call dispmsg
exit 0
;子程序
end start
4.使用其他寄存器
include io32.inc
.data
;数据定义
msg byte 'Hello ,World!',13,10,0
;msg byte '你好,瓜娃子!',13,10,0
.code
start:
;主程序
;mov eax,offset msg ;显示 这边为什么eax 为什么使用offset
mov ebx,offset msg
;mov ecx,offset msg
;mov eax,msg
call dispmsg
exit 0
;子程序
end start
这里看样子不行啊
include io32.inc
.data
;数据定义
msg byte 'Hello ,World!',13,10,0
msg2 byte '你好,瓜娃子!',13,10,0
.code
start:
;主程序
mov eax,offset msg ;显示 这边为什么eax 为什么使用offset
mov ebx,offset msg2
;mov ecx,offset msg
;mov eax,msg
call dispmsg
call dispmsg
exit 0
;子程序
end start
5.为什么使用offset 去掉行不行
include io32.inc
.data
;数据定义
msg byte 'Hello ,World!',13,10,0
;msg2 byte '你好,瓜娃子!',13,10,0
.code
start:
;主程序
;mov eax,offset msg ;显示 这边为什么eax 为什么使用offset
;mov ebx,offset msg2
mov eax,msg
call dispmsg
;call dispmsg
exit 0
;子程序
end start
看样子不太好使,eax为通用寄存器,主要是存放地址,直接将数据复制进去看来不太行。关于move ax @data
6.案例代码:推测应该是使用了子程序
;eg0201a.asm
include io32.inc
WriteString macro msg
mov eax,offset msg ;显示
call dispmsg
endm
.data
msg byte 'Hello, Assembly !',13,10,0 ;字符串
.code
start:
WriteString msg
exit 0
end start
以下为推测解释:
WriteString macro msg 到endm 为子程序
在start后面使用了该程序,但是并没有使用call命令并不是很能理解?
从反复使用msg却不报错的情况来看,应该不同段里面的指令是局部的,不是全局的。
自己写一遍
; eg0000.asm in Windows Console
include io32.inc
Printf macro msg
mov eax,offset msg
call dispmsg
endm
.data
; 数据定义
msg byte 'Hello,This is a small step',13,10,0
.code
start:
; 主程序
Printf msg
exit 0
; 子程序
end start
;报错历史
;前面定义Printf 后面使用printf 是会报错的,这里区分大小写
;move eax,msg 如果不写‘,’,写出move eax msg 报错errorA2008
;将mov 写成move
这里一定要注意是 move eax,offset msg 而不是move eax ,msg不然也报错
好吧,注意是mov eax。。。不是move eax
事实证明自己写报错无数。。。。。
7.案例代码:DOS代码
; eg0201d.asm in MS-DOS
include io16.inc
.data
msg byte '你好,汇编语言!',13,10,0 ;字符串
.code
start:
mov ax,@data
mov ds,ax
mov eax,offset msg ;显示
call dispmsg
exit 0
end start
用window控制台打开报错,果然呀~
8、/20181128更新:建议最好要本书啊,王爽的就行,该MOOC课程排课顺序有点不太建立体系,需要书建立体系。
include io32.inc
.data
count dword 12345678h,9abcdef0h,0,0,3721h
msg1 byte 'hello',13,10,0
.code
start :
;mov eax,33221100h
;mov ebx,eax
mov ebx,offset msg1
mov eax,ebx
;mov
call dispmsg
exit 0
end start
首先dispmsg应该是默认定义在了eax上,然后通过eax指向显示内容。eax为32位寄存器,保存的内容就是二进制32位的整数。所以直接将字符赋值给eax是不好使得。
之前定义msg byte 。。。然后mov eax,msg 相当于将msg第一个数据赋值给eax,而‘hello’不是32位。mov al,msg是可以的。
include io32.inc
.data
count dword 12345678h,9abcdef0h,0,0,3721h
msg1 byte 'hello world',13,10,0
.code
start :
mov eax,0h
;mov ebx,eax
mov al,msg1
;mov eax,ebx
;mov
call disprd
exit 0
end start
查了一下,'h’对应的acsii码为68h,al为8位寄存器,也就小段更改数据。