Skip to content

Latest commit

 

History

History
165 lines (132 loc) · 4.33 KB

File metadata and controls

165 lines (132 loc) · 4.33 KB

第22节 模块化的程序设计

❤️💕💕汇编语言目前仍在发挥着不可替代的作用,在效率上无可替代,在底层,学习linux内核,计算机外围设备和驱动,都离不开汇编。Myblog:http://nsddd.top


[TOC]

段值的确定

  1. 一个执行文件.exe在双击执行时,首先由操作系统分析本程序的段占用情况
    1. 包括多少段、各段长度、代码段第一条指令的偏移
  2. 然后在当前内存中寻找合适区域,并分配CS、DS、SS、ES等各段
  3. .exe执行文件中的数据调入内存DS段,代码调入内存CS段……..
  4. 然后把CPU的CS变为当前分配的代码段值,IP为第一条指令的偏移,从而开始程序的执行
  5. SP为堆栈段大小(即最大值-wB)
  6. 在汇编程序时,通过交叉文件可以看出各段大小。

模块化程序结构

汇编语言也是支持模块化程序设计,并非高级语言才可以。

assume cs:code
code segment
main: ...
      call sub1     ;调用子程序sub1
      ...
      mov ax, 4c00h
      int 21h

sub1: ...           ;子程序sub1开始
      call sub2     ;调用子程序sub1
      ...
      ret           ;子程序返回

sub2: ...           ;子程序sub2开始
      ...
      ret           ;子程序返回
code ends
end main

用寄存器来存储参数和结果

;计算data段中第一组数据的 3 次方,结果保存在后面一组dword单元中。
assume cs:code
data segment
    dw 1,2,3,4,5,6,7,8
    dd 0,0,0,0,0,0,0,0
data ends

code segment

start:mov ax,data
      mov ds,ax
      mov si,0      ;ds:si指向第一组word单元  dw
      mov di,16     ;ds:di指向第二组dword单元 dd

      mov cx,8		;循环处理
    s:mov bx,[si]	
      call cube		;调用cube
      mov [di],ax	;低十六位置
      mov [di].2,dx	;高十六位
      add si,2      ;ds:si指向下一个word单元
      add di,4      ;ds:di指向下一个dword单元
      loop s

      mov ax,4c00h
      int 21h
 cube:mov ax,bx		;求出bx的三次方,然后返回
      mul bx
      mul bx
      ret
code ends
end start

依次的进行编译链接执行,我们在后面-g看到后面的结果。

我们发现的问题,如果需要传递的数据有很多,寄存器不够了怎么办。可以用内存单元批量传递数据。

用内存单元批量传递数据

;将data段中的字符串转化为大写
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	;si的字节依次转化为大写
         inc si
         loop capital
         ret
code ends
end start

用栈传递参数

原理:由调用者将需要传递给子程序的参数压入栈中、子程序从栈中取得参数

;设 a = 3 、b = 1 ,计算:( a – b ) ^ 3 , a、b为word类型数据
assume cs:code
code segment
start:  mov  ax , 1
         push  ax
         mov  ax , 3
         push  ax         ;注意参数压栈的顺序
         call  difcube	  ;这个时候 把下一个IP压入栈,栈顶依旧走了一步  调用子程序
         mov ax,4c00h
         int 21h
difcube : 
	   push  bp		;bp基址指针寄存器,用于堆栈段寻址
	   ;很重要的一点:子程序要用dp,我们为了避免丢失有用数据。先入栈,返回前出栈
        mov  bp , sp
        mov  ax , [ bp + 4 ] ; 将栈中a的值送入ax 中
        sub   ax , [ bp + 6 ] ; 减栈中b的值
        mov  bp , ax
        mul  bp
        mul  bp	
        pop  bp		;bp可能在使用的时候主程序在用,所以我们可以用pop保证出去后不影响主程序的使用;恢复保存bp的值
        ret  4	;ret ip出栈,转移到后面执行
code ends
end start

指令ret n的含义 把栈后面的四个字节忽略掉,直接转移到后面去:

pop ip
add sp, n 

END 链接