INTEL 32位汇编 便利贴

本文随便整理,我们上微机原理之前没上汇编,无奈学校用的那本教材垃圾的超越想象力,根本就不是给初学者学习用的,整一个copy paste的产物,没头没尾,莫名其妙。所以只好整理一下Intel 汇编的知识了。本贴只是简单罗列,对他人作用不大。

 

首先是资料:在Visual Studio里面配置MASM

基本概念

程序运行

加载和执行:

  • OS找文件,并得到其基本信息
  • OS将文件载入内存
  • OS执行一条分支转移指令,使CPU从程序的第一条机器指令开始执行,同时创建了一个进程
  • OS见识进程并响应资源请求
  • 进程结束后OS删除句柄,释放资源

IA32的体系结构

操作模式

  • 保护模式: 所有指令和特性可用,程序具有独立的内存段,处理器阻止程序访问分配的段以外的其他内存
  • 实地址模式:可以任意访问内存
  • 系统管理模式:给开发操作系的人用的

基本执行环境

  地址空间:保护模式4G,实模式1M

  基本寄存器:

  • 8个通用寄存器:EAX,EBX,ECX,EDX,EBP(基址指针),ESP(栈指针),ESI(Source Index),EDI(Destination Index)。前四组可以寻址到8位(EAX,AX,AH,AL),后四组只能寻址到16位(ESI,SI)
  • 6个段寄存器:CS(Code),SS(Stack),DS(Data),ES,FS,GS
  • EFLAGS
  • 指令指针EIP(程序计数器)

  详细的说明:

  • EAX在乘除法时会自动被用
  • 有些指令使用ECX做循环计数器
  • ESP寻址栈上的数据,一般不用来做算术计算或者数据传送
  • ESI和EDI有高速内存数据传送指令使用(中文翻译作扩展源/目标指针)
  • EBP被高级语言用来做堆栈上的函数参数和局部变量引用,不应该用于算术运算和数据传送

  实模式下段寄存器用于存放段基址。保护模式下则存放描述符表的指针。

  EFLAGS是一系列标志,1时表示set了。0时表示reset了,标志包括:

  • CF 进位-无符号运算时目的数无法容纳时为1
  • OF 溢出-有符号运算溢出时为1
  • SF 符号-负数为1
  • ZF 零 -算术或逻辑运算为0时为1
  • AC 辅助进位 - 算术运算时8位数的第3位向第4位进位时为1
  • PF 奇偶- 结果的最低有效字节为1的位数为偶数时为1

内存管理

实模式

空间为0~FFFFF,段址和偏址都是16位,段址×16+偏址 = 绝对地址  08F1H:0100H = 09010H

保护模式

空间4GB,0~FFFFFFFF,masm中用flat模式。段寄存器存的是描述符表中的描述符。所有段都被映射到32位物理地址中。

一个程序至少要用2个段:代码段和数据段。段描述符存在全局描述符表中,是个64位的值。段界限符表示系统中物理内存数。在多段模式下每个进程都有自己的独立空间,界限副就保存期各自的空间。

此外,还有分页模式

 

汇编基础元素

常量

  默认十进制,可加后缀 10H, 10D, 10O, 10B

 

可用基本整数表达式

  ()+- * / MOD

 

字符和字符串常量

  'A', "A", "Goodnight" 'Goodnight'

 

保留字

  • 指令助记符,MOV。。。
  • 伪指令
  • 属性 BYTE。。。
  • 运算符
  • 预定义符号,@data, 编译时返回整数常量值

标识符

  标识变量、常量、过程。。

 

伪指令

  内嵌的特殊代码,如 DWORD .data .code .stack 100h(表示运行时栈的大小)

 

根据书上示例解释汇编程序结构

TITLE MASM Template (main.asm) ;TITLE是个注释整行的伪指令 ; Description: ; ; Revision date: INCLUDE Irvine32.inc .data ;数据段 myMessage BYTE "MASM program example",0dh,0ah,0 .code ;代码段 main PROC mov eax, 10000h add eax, 40000h sub eax, 20000h call DumpRegs exit ;exit 间接调用了一个ms-windows的函数来终止程序,由Irvine32.inc 定义 main ENDP ;标记main结束 END main ;END表明此行是汇编程序的最后一行,编译器将忽略该行后的所有内容,后面的main指明程序入口点的名字 

这个程序的另外一种更加详细的写法:

TITLE MASM Template (main.asm) ; Description: ; ; Revision date: .386 ;最低CPU要求是80386 .model flat, stdcall ; .model flat指定汇编器为保护模式生成代码, stdcall允许调用ms-windows函数 .stack 4096 ExitProcess PROTO, dwExitCode:DWORD ; PROTO指明此程序使用的过程原型ExitProcess是mswindows函数,用于退出进程. DumpRegs还是Irvine32的寄存器dump的过程 DumpRegs PROTO .code main PROC mov eax, 10000h add eax, 40000h sub eax, 50000h call DumpRegs INVOKE ExitProcess, 0 ; 调用过程,传参0作为返回值 main ENDP END main 

 

程序skelton

TITLE Program name (file name) ; desc ; author: ; create date; ; modified: ; mod date: author: INCLUDE Irvine32.inc .data ; var .code main PROC ; executable code exit main ENDP ; other proc END main 

 

汇编的过程

  1. 汇编器从源文件生成目标文件和列表文件
  2. 连接器读取目标文件从链接库里复制所需的过程和目标文件生成为可执行文件,还可以生成映像文件

列表文件包括程序的源代码、行号、偏移地址、翻译后的机器码和一个符号表,方便阅读

映像文件时包含被连接程序的分段信息的文本文件

 

定义数据

  MASM的基本内部数据类型

  • BYTE    - 8bits unsigned integer
  • SBYTE  - 8bits signed integer
  • WORD  - 16bits unsinged integer 实模式下作近指针 NEAR
  • SWORD - 16bits signed integer
  • DWORD - 32bits   (保护模式下做近指针)
  • SDWORD - 32bits
  • FWORD  - 48位整数(保护模式下作远指针)
  • QWORD  - 64bits integer
  • TBYTE     - 80bits integer
  • REAL4     - 32bits IEEE float
  • REAL8     - 64bits ..
  • REAL10   - 80bits .

   还有DB,DW,DD(32bits 整数或实数),DQ(64bits 整数或实数),DT (10字节)

定义

var1 BYTE 'A' var2 BYTE ? ;不初始化 vard WORD 65535 vard1 SWORD -32768 varf REAL4 -2.1 varf1 REAL10 4.6E-400 varl1 BYTE 10,20,30,40 ;初始化多个值,每个向后偏移一个地址 ;定义字符串 str1 BYTE "GO TO", 0 str3 BYTE 'no',0 ;在多行定义字符串 str4 BYTE "HEY, this is a " BYTE "multi-line string",0dh,0ah, ; 0dh 0ah表示/r/n BYTE "See the reault" 0 ;初始化多个空间 var3 BYTE 20 DUP(0) ; 定义20字节全部初始化为0 var4 BYTE 4 DUP("STACK") ; "STACKSTACKSTACKSTACK" ;intel 使用little endian ; 12345678H ; 0000: 78 ; 0001: 56 ; 0002: 34 ; 0003: 12 

注意的是,虽然课本上说字符串多行定义可以,但是实际上,貌似多行定义了以后用LENGTHOF操作只能得到一行的结果。这个需要进一步考证。

 

符号常量

符号常量实际上不占用存储空间,也不能修改

有三种伪指令用于这个: = EQU TEXTEQU

;name = expression name会被直接替换, = 可重定义, COUNT = 100 mov ax, COUNT ;编译结果是 mov ax,100 ;还可以通过和dup结合漂亮的定义数组 array1 COUNT DUP(0) ;计算数组的大小 list DWORD 10,30,33 ListSize = ($ - list) /4 ; $表示当前语句地址偏移值, /4因为DWORD4字节 ;---------------------------------- ;name equ experssion ; expression 是表达式 ;name equ <text> ; text是文本 ;equ不能重定义 ;-----------------------------------  

 

汇编语句基础

基础操作

 

基本运算指令

  • INC/ DEC 自增自减
  • ADD 目的数,源     源加到目的数上
  • SUB 目的数,源
  • NEG 求相反数(按位取反后+1,也就是求补)

符号位影响

  • CF表示无符号整数运算是否溢出
  • OF表示有符号整数运算是否溢出
  • ZF表示结果是否为0
  • SF表示结果是否为负
  • PF表示目的操作数最低字节中的1是否偶数个

MOV系列

MOV系列都是数据传送指令,包括MOV, MOVZX, MOVSX

MOV指令有一些规则必须遵守:

  • 两操作数尺寸相同
  • 两操作数不能同时为内存操作数
  • 目的操作数不允许是CS,EIP,IP
  • 立即数不能直接送段寄存器(保护模式下不允许操作段寄存器)

对于尺寸不同的数之间数据传送就必须使用MOVZX和MOVSX,MOVZX是零扩展传送,也就是适用于传送无符号整数,指令会用0填充高位。而对于有符号数则用MOVSX

 

类似一个功能的是XCHG指令,用来交换两个操作数,但是注意它的两个操作数不能同时是内存操作数。

 

其他数据操作符

  • OFFSET 返回一个变量相对于其所在段的开始地址的偏移量
  • PTR 重载变量的默认尺寸
  • TYPE 返回数组中每个原书的大小(字节数)
  • LENGTHOF 返回数组内元素的个数 
  • SIZEOF 返回数组初始化时占用的字节数 = lengthof * Type

寻址

; 间接寻址 .data var BYTE 10h .code mov esi, OFFSET var ;esi存放var的偏移地址 mov al, [esi] ; mov al, var ; 间接寻址也可用于方便的遍历数组 .data arr BYTE 10,30,50,80 .code mov esi, OFFSET arr mov al, [esi] ; al= 10 inc esi mov ah, [esi] ; ah = 30 ;变址操作数(indexed operand) 把常量和寄存器相加得到一个有效地址,使用任意的32位通用寄存器作为变址寄存器 ; 格式 constant[reg] 或[constant + reg] array[esi] ;等价 [array + esi] ;对于不是一个字节的元素 array2[esi*4] ;第四个DWORD  

 

循环和条件

  • jmp 无条件跳 
  • loop 使用ecx做计数器每次循环减1. 具体步骤是先ecx自减1,后看看是否为0,不是则调整到目的地址,否则不跳转。loop的跳转范围为-128~127字节(约42条指令)

使用loop做数组求和的例子

TITLE sum (sum.asm) INCLUDE Irvine32.inc .data intarr WORD 100h, 200h, 300h, 400h .code main PROC mov edi, OFFSET intarr ; intarr 的地址 mov ecx, LENGTHOF intarr ; 循环计数器 mov eax, 0 ; 累加器清零 L1: add eax, [edi] ;sum += intarr[edi] add edi, TYPE intarr ; 数组下标+1 loop L1 exit main ENDP END main 

 

过程和条件处理

前提知识

运行时栈

CPU直接管理的内存数组,使用SS和ESP两个寄存器保护模式下,SS存段选择子ESP存的是只想堆栈内特定位置的一个32位偏移值,也就就是栈顶了。一般无需手工操作。运行时栈的增长是负的,也就是每压入一个值,栈顶指针ESP减小(一般是4)

对运行时栈的操作有PUSH POP, PUSHFD POPFD, PUSHAD PUSHA POPAD POPA这些

  • PUSH压入16位或32位操作数,保护模式下总是32位的。
  • PUSHFD用来压入32位的EFLAGS寄存器的值
  • PUSHAD 按一下顺序压入寄存器:EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI
  • PUSHA类似的压入:AX, CX, DX, BX, SP, BP, SI, DI

定义和使用过程

汇编里的过程相当于高级语言里的函数。


 

procname PROC procname ENDP ; 除了main之外的过程都应该用ret返回 ; main调用了ExitProcess结束进程 ; 过程的返回值和参数通常都用寄存器保存 ; C和C++ 典型情况下使用AL返回8位值,AX返回16位值,EAX返回32位值 

    所以,调用过程无法就是给寄存器赋值,再call一下。

此外,还可以使用USES 操作符来为PROC伪指令指定要使用的寄存器,它会自动生成push和pop相应寄存器的命令。这个操作符只需要写在PROC伪指令后面就可以

条件处理

相关指令

  • AND dest, src   . 总是清除溢出标志和进位标志, 操作数尺寸必须相同
  • OR                   . 总是清除溢出和进位标志
  • XOR                  .异或
  • NOT reg[mem]  .按位取反
  • TEST                  .在每对操作数之间执行隐含的与操作,并置标志位。和AND的区别在于不修改目的操作数。
  • BT,BTC,BTR,BTS  . 。。。 暂时用不到
  • CMP                   . 在每对操作数间进行隐含减法操作, 不修改操作数.

;test 来测试位 test a1, 00001001b ;测试0和3位是否为0,仅当两个都为0时,ZF = 1 ;cmp 测试源和目标是否相等,隐含把目标数-源, 无符号数情况如下: mov ax, 5 cmp ax, 10 ; ZF= 0 CF =1 cmp ax, 5 ; ZF = 1 CF = 0 cmp ax, 3 ; ZF = 0 CF = 0 ; 有符号数情况如下: mov ax, -5 cmp ax, -3 ; SF!= OF cmp ax, -8 ; SF = OF cmp ax, -5 ; ZF = 1 

条件跳转指令

条件跳转都是成对的比如jz 就对应一个jnz,MASM要求跳转的目的地址在本过程内

  • jz : if(ZF == 1) jump
  • jc : if (CF == 1) jump
  • jo : if (OF == 1) jump
  • js : if( SF == 1) jump
  • jp : if( PF == 1) jump
  • je : 相等(CMP结果)则跳转
  • jne: cmp 不等则跳
  • jcxz: cx = 0 则跳
  • ------------无符号数比较
  • ja : if (left > right ) jump
  • jae: if(left >= rhight) jump
  • jb : if( left < right) jump
  • jbe :..
  • jnbe = ja
  • -------------有符号数比较
  • jl : cmp 小于则跳
  • jg : cmp 大于则跳转
  • jge :..

 

 

------------------------------------------未完待续-------------------------------------------------

p.s 贴出暂时要用的程序,从给定字符串计算某个子串出现的次数,写的不好,欢迎指正。

;--Short Assembly program for counting the occurrences of specific substring-- ;Author: Wu Yanxiang ;ID: 0715232024 ;ENV: VC++ 2010 + MASM 8.0 ;TEST case: Pass TITLE SUBSTRINGCNT (main.asm) INCLUDE Irvine32.inc .data INPUTSTR DB "SOME DAY HAVE SHINING SUN DOESNT MEANS ITS A SUNNY DAY UNLESS THE SUN MAKE ME SO CONFORTABLE", 0dh, 0ah, 0 SUBSTRC DB "SUN", 0 OUTPUT DB "SUN:", 0 SUBSTRCNT DD 0 ;occurrence of SUBSTRC FORI DD 0 ; for int i = 0 ... LENSUB DD 0 ; length of sub string LENTOTAL DD 0 ; length of entire string .code main PROC call HASSUBSTR mov edx, OFFSET OUTPUT call WriteString call WriteINT ;invoke system api by process defined in irvine32 exit main ENDP ;----------------------------------------------------- HASSUBSTR PROC USES esi ecx edx ebp ; ; count the occurrence times of SUBSTRC in INPUTSTR ; Return: eax ;----------------------------------------------------- mov LENTOTAL, LENGTHOF INPUTSTR mov LENSUB, LENGTHOF SUBSTRC dec LENTOTAL dec LENSUB mov ecx, LENTOTAL sub ecx, LENSUB inc ecx mov esi, 0 L1: mov dl, 1 ;indicates whether find a substring push ecx mov ecx, LENSUB mov edi, 0 mov esi, FORI L2: mov bl, INPUTSTR[esi] mov bh, SUBSTRC[edi] inc esi inc edi cmp bl, bh jne NOTEQUAL loop L2 jmp L1P2 NOTEQUAL: mov dl, 0 jmp L1P2 ;-------L2END--------------- L1P2: pop ecx cmp dl, 0 jne CONHAS inc FORI loop L1 jmp L1EXIT CONHAS: inc SUBSTRCNT mov ebx, LENSUB add FORI, ebx sub ecx, ebx inc ecx loop L1 L1EXIT: mov eax, SUBSTRCNT ret HASSUBSTR ENDP END main 

你可能感兴趣的:(INTEL 32位汇编 便利贴)