Skip to content

Latest commit

 

History

History
217 lines (167 loc) · 6.95 KB

7.更灵活的定位内存地址的方法.md

File metadata and controls

217 lines (167 loc) · 6.95 KB

王爽汇编第七章,更灵活的定位内存地址的方法

[toc]

and 和 or指令

image-20210917145344213

关于ASCII码

ASCII(发音: /ˈæski/ ASS-kee[1]American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统。它主要用于显示现代英语,而其扩展版本延伸美国标准信息交换码则可⒗以部分支持其他西欧语言,并等同于国际标准**ISO/IEC 646**。

ASCII 由电报码发展而来。第一版标准发布于1963年[3][4],1967年经历了一次主要修订[5][6],最后一次更新则是在1986年,至今为止共定义了128个字符;其中33个字符无法显示(一些终端提供了扩展,使得这些字符可显示为诸如笑脸、扑克牌花式等8-bit符号),且这33个字符多数都已是陈废的控制字符。控制字符的用途主要是用来操控已经处理过的文字。在33个字符之外的是95个可显示的字符。用键盘敲下空白键所产生的空白字符也算1个可显示字符(显示为空白)。

img

显示hello,world!

注意这里我调用了int 21h,这是一个DOS的中断,其中ah=09是他的功能号用来打印字符串。

关于DOS中断的内容会在后续章节详细介绍。

assume  cs:code,ds:data
;>>>>>>>>>>>>>>>>
;数据段
;>>>>>>>>>>>>>>>>
data segment
  db 'hello,world!','$'
data ends

;>>>>>>>>>>>>>>>>
;代码段
;>>>>>>>>>>>>>>>>
code segment
start: 
      mov ax,data
      mov ds,ax
      
      ;调用DOS中断显示字符串
      mov dx,0 ;ds:[dx]
      mov ah,09h
      int 21h
      ;return dos
      mov ax,4c00h
      int 21h
code ends
end start

image-20210917162102218

大小写转换

小写字母的ASCII码值比大写字母的ASCII码值大20H(32)

大写字母ASCII码的第5位为0,小写字母的第5位为1(其他一致)

在这里插入图片描述

;**********************************
;*                                *
;* 要求:将所有字符串转换成小写字符串  *
;**********************************

assume cs:code,ds:data
;>>>>>>>>>>>>>>>>>
;数据段
;>>>>>>>>>>>>>>>>>
data segment
	db 'Hello,World!','$'
data ends
;>>>>>>>>>>>>>>>>>
;代码段
;>>>>>>>>>>>>>>>>>
code segment
main:
	 mov ax,data ;ds段
	 mov ds,ax
	 
	 ;大小写转换
	 mov bx,0
	 mov cx,11
  s: mov al,ds:[bx] ;将ASCII码从 ds:bx单元中取出
	 or al,00100000b;让第5位无论如何都变1
	 mov ds:[bx],al
	 inc bx
	 loop s
	 
	 ;输出字符串
	 mov dx,0; ds:[0]
	 mov ah,09h
	 int 21h
	 
	 ;retun 2 dos
	 mov ax,4c00h
	 int 21h
code ends
end main

image-20210917164830501

[bx+idata]寻址

在前面,我们用[bx]的方式来指明一个内存单元,还可以用一种更为灵活的方式来指明内存单元:[bx+idata]表示一个内存单元,他的偏移地址为(bx)+idata [bx中的数值加上数字]

例如: mov ax,[bx+200]

也可以写成如下的格式:(注意这里指的是masm所支持的伪指令,具体其他编译器看情况而定.)

mov ax,[bx+200]
mov ax,[200+bx]
mov ax,[bx].200
mov ax,200[bx]

[bx+idata]处理数组例子:

;*************************************
;*                                   *
;*    将如下的doSASM转换成DOSasm       *
;*************************************

assume cs:code,ds:data

;>>>>>>>>>>>>>>>>>>>>>
;数据段
;>>>>>>>>>>>>>>>>>>>>>
data segment
    db 'doS'
    db 'asm','$'
data ends

;>>>>>>>>>>>>>>>>>>>>>
;代码段
;>>>>>>>>>>>>>>>>>>>>>
code segment
main:
      ;
      mov ax,data
      mov ds,ax

      ;大小写转换
      mov bx,0
      mov cx,3
    s:mov al,0[bx]
      and al,11011111b;转大写
      mov 0[bx],al
      mov al,3[bx];
      or al,00100000b;转小写
      mov 3[bx],al
      inc bx
      loop s 

      ;输出字符串
      mov dx,0
      mov ah,09h
      int 21h

      ;return 2 DOS
      mov ax,4c00h
      int 21h
code ends
end main

翻译成C语言

#include <stdio.h>
int main()
{
   char a[]="doS";
   char b[]="ASM";

   int i=0;
   do
   {
		a[i] = a[i] & 0xDF;
		b[i] = b[i] | 0x20;
		i++;
   }while(i<3);

   printf("%s%s\n",a,b);
   return 0;
}

image-20210917173600164

si和di

这两个寄存器其实之前介绍寄存器篇章的时候,已经介绍过了,si和di都是偏移寄存器并且注意在x86架构下,他们是字符串相关的寄存器。

image-20210918092750068

不同的寻址方式的灵活应用

如果我们比较一下前面用到的集中定位内存地址的方法(可以称为寻址方式),就可以发现:

  • [idata]用一个常量来表示地址,可用于直接定位一个内存单元;
  • [bx]用一个变量来表示内地地址,可用于间接定位一个内存单元(比如循环);
  • [bx+idata]用一个变量和常量表示地址,可在一个起始地址的基础上用变量间接定位一个内存单元(比如多个数组);
  • [bx+si]用两个变量表示地址;
  • [bx+si+idata]用连个变量和一个常量表示地址。

可以看到,从[idata]一直到[bx+si+idata],我们可以用更加灵活的方式来定位一个内存单元的地址。这使得我们可以从更结构化的角度来看待所要处理的数据。

参考文献: https://blog.csdn.net/trochiluses/article/details/20008631 int 21——dos系统调用 表 https://blog.csdn.net/qq_39654127/article/details/88698911 王爽汇编笔记 《王爽汇编第4版》 第7章