立即数:可以立即在一条机器指令后找到具体数值的数,如内存中00位写着加指令,01位写着1100_1111,意思就是将1100_1111(十进制207)加到某处,反之可以表示数据的地址。
低端字节序:16位寄存器数据存入内存(内存单位为8位),寄存器低位存入内存低位(如00)高位存入内存高位(如01),内存到寄存器同样
程序的重定位难题:当内存中的数据因为某种情况需要移动时,只是简单地将内存地址(绝对内存地址)写到指令中就不行了,会导致重定位错误。
为了解决重定位问题,使用[段地址:偏移地址]来描述数据的地址
此时如果发生内存数据的移动(以段为单位进行移动),只需要改变段地址的内容,就还可以定位到数据(有点像C中的宏定义)
8086的分段机制:有两个寄存器CS和DS,分别存放代码段和数据段的具体段地址,但是内存地址提供了20根地址线,而两个段寄存器只有16位(如CS可表示0XAB12,而内存地址却为0XAB120)。将内存地址右移4位(吞掉末位的那个0)来存入段寄存器,取出时再左移4位(补上末位0),这样段地址就存入了寄存器,再通过指针指令寄存器IP表示偏移地址,[CS:IP]表示出代码地址
因此对于一个数据,可以由多个段+偏移来表示
Notepad++集成nasm编译:运行 -> 运行 -> 输入cmd /k pushd “KaTeX parse error: Expected 'EOF', got '&' at position 22: …NT_DIRECTORY)" &̲ E:\NASM\nasm.e…(FULL_CURRENT_PATH)” -o “$(NAME_PART).bin” & PAUSE & EXIT 保存 -> 设置快捷键
8086内存地址分配:
8086加电复位时处理器向内存发出的指令是FFFF0,距离内存结束只有16字节,这16字节存放有跳转指令,在跳转的目的地,一般会把磁盘的0头0柱1扇区(主引导扇区)的数据加载到那里,以此执行对应的程序。
填充主引导扇区的512字节来作为初始程序,若不满足512字节,则不识别,同时,必须以0XAA55结尾
mov ax, 0x30
mov dx, 0xc0
add ax, dx
times 510-($-$$) db 0 ;$为当前地址,$$为汇编文件开始的段地址,($-$$)表示本行的段内偏移量,填充0
dw 0xaa55
标号:汇编代码由三个可选的部分组成 标号-指令-注释,标号表示离他最近的下一指令的地址
上段代码等效于
start:
mov ax, 0x30
mov dx, 0xc0
add ax, dx
current:
times 510-(current-start) db 0
dw 0xaa55
逻辑块地址:物理上磁盘分为柱面-磁头-扇区(CHS),但是表示困难,所以采用逻辑块地址(LBA)的方式表示,即对每个扇区编号
屏幕显示文字:显存中存放屏幕显示的相关内容数据,显存映射到内存的地址中
mov ax, 0xb800
mov ds, ax
mov byte [0x00], 'l' ;向显存映射到内存的地方写数据,默认在ds表示的段中写
mov byte [0x01], 0x02;0x01只是偏移地址,无法确定操作的位数,0x04同样可以理解为0x0004,无法确定位数,所以需要加byte指定以字节进行mov
;如果操作数之一确定了操作的位数(如固定位数的寄存器)则不需要指定位数
mov byte [0x02], 't'
mov byte [0x03], 0x02
mov byte [0x04], 'y'
mov byte [0x05], 0x02
;mov指令不允许在内存单元之间直接传输数据
times 510-($-$$) db 0
dw 0xaa55
使用nasm xxx.asm -l xxx.lst
生成汇编代码的列表文件,方便观察汇编后数据和代码的对应关系
汇编地址:每条指令在程序汇编阶段确定的地址
段间直接绝对跳转指令:jmp 段地址:偏移地址
如设置jmp 0x0000:0x7c00
则将跳转至主引导扇区开头重新执行
mov ax, 0xb800
mov ds, ax
...
jmp 0x0000:0x7c00+$ ;段间直接绝对跳转指令,使处理器卡在本行程序
times 510-($-$$) db 0
dw 0xaa55
绝对间接近跳转:使用寄存器对绝对偏移地址进行间接存储,只能在CS表示的当前段内跳转
mov ax, 0xb800
mov ds, ax
...
mov bx, 0x7c00+again
again:
jmp bx
times 510-($-$$) db 0
dw 0xaa55
使用相对偏移量的短/近跳转:使用标号
mov ax, 0xb800
mov ds, ax
...
again:
jmp again ;近跳转用jmp short 8位跳转相对偏移量,远跳转用jmp near 16位跳转相对偏移量,不加自动识别
times 510-($-$$) db 0
dw 0xaa55
无符号除法:
- 操作数8位(除数)-被除数16位:AX ÷ 操作数 = AL···AH
- 操作数16位(除数)-被除数32位:DX_AX ÷ 操作数 = AX···DX
- 操作数32位(除数)-被除数64位:EDX_EAX ÷ 操作数 = EAX···EDX(8086不支持,80386开始支持)
- 操作数64位(除数)-被除数128位:RDX_RAX ÷ 操作数 = RAX···RDX(8086和32位处理器不支持,6位处理器支持)
mov ax, 0xffff
mov bx, 10
mov cx, 0
mov ds, cx
;除5次bx,从而取出单个数字,存入内存
xor dx, dx
div bx
add dl, 0x30
mov [0x7c00+buffer], dl
xor dx, dx
div bx
add dx, 0x30
mov [0x7c00+buffer+1], dl
xor dx, dx
div bx
add dx, 0x30
mov [0x7c00+buffer+2], dl
xor dx, dx
div bx
add dx, 0x30
mov [0x7c00+buffer+3], dl
xor dx, dx
div bx
add dx, 0x30
;ds标识结果各数字段(0x0000)es标识显存段(0xb800)
mov cx, 0xb800
mov es, cx
mov [es:0x00], dl
mov byte [es:0x01], 0x02
mov dl, [0x7c00+buffer+3]
mov [es:0x02], dl
mov byte [es:0x03], 0x02
mov dl, [0x7c00+buffer+2]
mov [es:0x04], dl
mov byte [es:0x05], 0x02
mov dl, [0x7c00+buffer+1]
mov [es:0x06], dl
mov byte [es:0x07], 0x02
mov dl, [0x7c00+buffer]
mov [es:0x08], dl
mov byte [es:0x09], 0x02
buffer:
db 0, 0, 0, 0
jmp 0x0000:0x7c00+$
times 510-($-$$) db 0
dw 0xaa55
串传送指令:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i3wILzQV-1691295231112)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230729144708214.png)]
jmp start
text:
db 'l', 0x02, 't', 0x02, 'y', 0x02
start:
mov ax, 0x7c0 ;本段物理地址为0000:7c00,即7c00,当ds取0000时必须标号前加7c00,当ds取07c0时0偏即7c00,汇编地址即物理地址,标号前不用加7c00
mov ds, ax
mov ax, 0xb800
mov es, ax
cld ;设定传送方向为低地址向高地址(标志寄存器清零),反之为std(标志寄存器置位)
mov si, text ;原始位置偏移地址
mov di, 0 ;目标位置偏移地址
mov cx, (start-text)/2 ;控制重复执行movsw几次
rep movsw
jmp $
times 510-($-$$) db 0
dw 0xaa55
循环
number:
db 0, 0, 0, 0, 0
start:
mov ax, number
mov bx, ax
mov si, 10 ;除数
mov cx, 5 ;控制循环次数
lab:
xor dx, dx
div si
mov [bx], dl ;bx又叫基址寄存器,可用来寻址
inc bx ;自增,dec自减
loop lab
jmp $
times 510-($-$$) db 0
dw 0xaa55
求补码:neg 寄存器或内存地址
有符号除法指令:idiv 除数
,除适用有符号数外,同无符号除法
余数的符号始终与被除数相同
标志寄存器:
使用栈进行数位分解并显示
xor cx, cx
mov ss, cx ;栈的段地址0x0000
mov sp, cx ;栈顶初始地址0x0000,每次入栈sp减2(16位,2字节),高地址向低地址移动
mov bx, 10
xor cx, cx
; 分解数位
lab:
inc cx ;记录入栈次数
xor dx, dx
div bx
add dl, 0x30
push dx ;入栈,16位处理器出入栈必须16位
cmp ax, 0 ;判断ax是否被除完
jne lab
show:
pop dx
mov [es:di], dl
inc di
mov byte [es:di], 0x02
inc di
loop show
就像[BX]
直接表示DS段内存相应偏移量下内容一样,使用[BP]
直接表示SS段内存的值
mov bp, sp
mov dx, [bp+2]
几种寻址方式:
mov ax, cx
两个操作数都是寄存器寻址add bx, 0xf000
右操作数是立即数寻址,标号会直接编译成地址,所以也是立即数寻址- 内存寻址
mov ax, [es:0x50c0]
右操作数是直接(内存)寻址inc word [ss:bx+2]
使用基址寻址mov [si+lab], dx
用SI或DI进行内存寻址(DS段),变址寻址mov ax, [bx+si+0x03]
基址变址寻址