学汇编,记笔记(六)《汇编语言》王爽著——定位内存地址_存储字符串_大小写转换_循环嵌套_二维数组问题

1,129 阅读5分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

前言

学习教材:《汇编语言(第4版)》王爽著 此笔记是书中内容+自我总结,方便查阅和复习 请支持原著

章末实验

一、位运算

汇编支持按位与、按位或运算

mov al,00111010b ;以b声明二进制

and al,11011101b ;按位与
or al,11011101b ;按位或

运算需要声明二进制,运算结果覆盖存储到第一个指明的位置

二、存储字符(串)

字符以十六进制ASCII码存储在内存单元内,一个字符占一个字节(8 bits)

使用类似以下代码声明字符(串)常量

datasg segment
	db 'Hello World!' ;db字节型
datasg ends
codesg segment
	mov al,'a' ;等效于mov al,61H,存储到半个ax
codesg ends

这些代码实质上使用了对应字符(串)的ASCII码

三、字符(串)的大小写转换

大小写字符的ASCII码相差32(20H,100000B),一般方法是通过判断当前的大小写类型进而采取加或减

而32是二进制第六位,因此采用位运算转换无需判断其状态直接转换,且会自动跳过无需转换的字符

字符二进制
A0100 0001
a0110 0001

由于真值和位运算的特性,大小写转换的运算不同,置1用按位或,置0用按位与

Ⅰ、大写转小写

大写转小写只将第六位的值置1,使用按位或

mov al,'A'
or al,00100000b

Ⅱ、小写转大写

大写转小写只将第六位的值置0,使用按位与

mov al,'a'
and al,11011111b

四、SI和DI寄存器

SI和DI类似通用寄存器,是十六位寄存器。但区别是无法拆分为两个八位寄存器

五、[bx+si+idata]定位内存地址

mov ax,[bx+si+idata]

[bx+si+idata]表示一个内存单元,它的偏移地址是(bx)+(si)+idata,总地址是((ds*16)+(bx)+(si)+idata)

还有以下写法,可均为0,其中bx和si是变量,间接定位;idata是常量,直接定位

定位内存的多种写法

mov ax,[bx+123+si]
mov ax,[123+bx+si]
mov ax,123[bx][si]
mov ax,[bx].123[si]
mov ax,[bx][si].123 ;类比C结构体

六、尝试循环灵活定位

编程,将datasg段中的每个单词转换为小写,每个单词用空格扩展到16字节

...
datasg segment
	db 'ABC             '
	db 'DEF             '
datasg ends
...

这个问题实质是一个二维数组问题

首先需要循环两次,每次遍历三个字符,是一个循环嵌套问题。而循环次数只能存储在cx内,cx只有一个,因此会导致覆盖外层循环。

对于多重循环,在执行内层循环时,将外层循环的cx计数值存储,重新赋值循环,内层循环结束后再取出存储的cx计数值,重新赋值给cx进行外层循环

存储可以使用寄存器,但若嵌套循环过多超过总寄存器数就无法完成。因此,应采用内存来记录存储cx值。一般来说,存储数据都应该使用内存,而且是栈空间。

实现代码如下:

assume cs:codesg,ds:datasg,ss:stacksg

datasg segment
	db 'ABC             ' ;长16字节
	db 'DEF             ' ;长16字节
datasg ends

stacksg segment
	dw 0,0,0,0,0,0,0,0 ;将栈段扩充到16字节的正整数倍,此处为8字(16字节)
stacksg ends

codesg segment
start:
	mov ax,stacksg
	mov ss,ax ;指向栈段
	mov sp,10h ;指向栈底,偏移量16
	
	mov ax,datasg
	mov ds,ax ;指向数据段
	
	mov bx,0 ;作为行号,共两个字符串
	mov cx,2 ;外循环,两个字符串,共两次
s:
	push cx ;外循环次数入栈
	mov si,0 ;作为列号,每串共三个字符
	mov cx,3 ;内循环,三个字符,共三次
s0:
	mov al,0[bx][si] ;对每一行,依次取出前三个字符
	or al,00100000b ;转换小写
	mov 0[bx][si],al
	
	inc si ;列号自增1,接着取出下一位字符
	loop s0
	
	add bx,10h ;行号自增16,由于每个字符串共16字节,直接偏移16到达下一行
	pop cx ;外循环次数出栈,准备外循环
	loop s
	
	mov ax,4c00h
	int 21h
		
codesg ends
end start

七、二维数组的定位

对于0[bx][si]表示法在二维数组中的应用非常方便

以上一题为模板,bx行号si列号,至于0,由于字符串是从头开始的,因此idata值为0,若不是从头开始就需要将0改成其他值

如字符串'1.abc',此时进行循环就需要用2[bx][si]指向第三位

注意相差1,此处表示向高位的偏移量为2,偏移前指向数字1,偏移后指向字符a

后记

  • 偏移地址[bx+si+idata]的灵活使用
  • 暂存数据需要使用栈空间
  • SI和DI无法拆分成两半
  • 循环嵌套需要将cx入栈