曲曲的秘密学术基地

纯化欲望、坚持严肃性

欢迎!我是曲泽慧(@zququ),目前在深圳(ICBI,BCBDI,SIAT)任职助理研究员。


病毒学、免疫学及结构生物学背景,可以在 RG 上找到我已发表的论文

本站自2019年7月已访问web counter

汇编语言 10.11 10.12 批量数据的传递 寄存器冲突问题

10.11 批量数据的传递

子程序中如果只要一个参数,可以放在寄存器bx中。但是如果应对多个数据需要传递,由于寄存器的数量终究有限,我们不能简单地用寄存器存放多个需要传递的数据。对于返回值,也同样有相同的问题。

这种情况,我们将批量数据放到内存中,然后将它们所在的内存空间地址放在寄存器中,传递给需要的子程序。对于具有批量数据的返回结果,也可以用同样的方法。

问题: 设计一个子程序,功能:将一个全是字母的字符串转化为大写。

分析:

这个子程序需要知道两件事,字符串的内容和字符串的长度。因为字符串中的字母可能有很多,所以不便将整个字符串中的所有字母都直接传递给子程序。但是可以将字符串在内存中的首地址放在寄存器中传递给子程序。因为子程序中要用到循环,我们可以用loop指令,而循环的次数恰恰就是字符串的长度。处于方便,我们把字符串的长度放在cx中。

子程序代码如下:

capital: and byte ptr [si], 11011111b    ;将目标字符改写为大写
        inc si                          ;指向目标字符的下一个字符
        loop captal                     ;直至改写全部字符
        ret

完整代码如下,

assume cs:code
data segment
  db 'conversation'
data ends

code segment
  start: mov ax, data
         mov ds, ax
         mov si, 0
         mov cx, 12
         call capital
         mov ax, 4c00h
         int 21h

capital: and byte ptr [si], 11011111b
         inc si
         loop capital
         ret
code ends
end start

除了寄存器传递参数外,还有一种通用的方法是用栈来传递参数。

10.12 寄存器冲突的问题

设计一个子程序,功能:讲一个全是字母,以0结尾的字符串,转化为大写。

程序要处理的字符串以0作为结尾符,这个字符串可以如下定义:

db 'conversation', 0

应用这个子程序,字符串的额内容后面以一定要有一个0,标记字符串的结束。子程序可以依次读取每个字符进行检测,如果不是0,就进行大写的转化;如果是0,就结束处理。由于可通过检测0而直到是否已经处理完整个字符串,所以子程序可以不需要字符串的长度作为参数。这时可以用jcxz来检测0。

;说明:讲一个全是字母,以0结尾的字符串,转化为大写
;参数:ds:si指向字符串的首地址
;结果:没有返回值

captial: mov cl, [si]
         mov ch, 0    ;寻找cx = 0000时,执行jcxz命令
         jcxz ok
         and byte ptr [si], 11011111b
         inc si
         jmp short capital
     ok: ret

子程序的应用,将数据段中的字符串全部转化为大写。

assume cs:code
data segment
  db 'word', 0
  db 'unix', 0
  db 'wind', 0
  db 'good', 0
data ends

应用子程序后的代码段为,

code segment
  start: mov ax, data
         mov ds, ax
         mov bx, 0

         mov cx, 4
      s: mov bx, 0
         call capital
         add bx, 5
         loop s

         mov ax, 4c00h
         int 21h
capital: push cx
         push si

 change: mov cl, [si]
         mov ch, 0
         jcxz ok
         and byte ptr [si], 11011111b
         inc si
         jmp short change

     ok: pop si    ;这里注意寄存器入栈和出栈的顺序
         pop cx
         ret

要小心实际上的一般化问题:子程序中使用的寄存器很可能会造成与主程序中的寄存器之间的冲突。

解决方案:

在子程序开始将子程序中所有用到的寄存器中的内容都保存起来,在子程序返回前再回复。这样用栈来保存寄存器中的内容。

以后,编写的框架如下:

子程序开始时:子程序中使用的寄存器入栈
              子程序内容
              子程序中使用的寄存器出栈
              返回(ret、retf)

要注意寄存器入栈和出栈的顺序

Last One

python 魔法方法 (5) 属性访问

整理自小甲鱼鱼C论坛属性访问操作,getattr(),setattr()以及delattr()函数通常可以通过(.)操作符的形式去访问对象的属性。>>> class C: def __init__(self): self.x = 'RED'>>> c = C()>>> c.x'RED'>>> getattr(c, 'x', '没有这个属性')'RED'>>> getattr(c, ...…

pythonMore
Next One

汇编语言 10.7-10.10 call和ret的配合使用 mul 模块化 参数和结果传递的问题

10.7 call和ret的配合使用问题(1) 下面程序返回前,bx中的值是多少?assume cs:codecode segmentstart: mov ax, 1 mov cx, 3 call s mov bx, ax mov ax, 4c00h int 21h s: add ax, ax loop s retcode endsend start分析程序运行的过程: CPU将call s 指令的...…

汇编语言More