汇编语言 基于x86处理器 第三章

第一个汇编语言程序:

Main PROC

  Mov eax,5

  Add   eax,6

 

  INVOKE ExitProcess,0

Main ENDP

加上变量: ;程序有代码段,数据段,还会有堆栈段

.data                 ;.data.code段(和PE文件格式有点关系)

sum DWORD 0 ;变量定义

.code

Main PROC

  Mov eax,5

  Add eax,6

  Mov sum,eax

 

  INVOKE ExitProcess,0

Main ENDP

 

算术优先级:

(), 一元+-, */, MOD, +- ;一元加减指 -5,+9此类

 

常数声名:

[ { + | - } ] digits [ radix ] ;radix指进制符号: h,q/o,d,b 默认下为十进制

比如:

  26d

  11010011b

 

实数常数声名:

Sign { + | - }

Exponent E [ { + | - } ] interger

比如:1.0  +3.0 -44.2E+05 26.E5

 

字符串常量声名:

‘ABC’ ‘X’ “4096” “This isn’t a test”

保留字≈关键字

标识符:

例如上文中的sum变量 或是(loop)

  loop:

    jmp loop

 

伪指令不作为指令执行,用于定义变量、宏和子程序等操作(下文伪指令 与 指令)

Cont DWORD 26

Mov eax, Cont

.386               ;表示这是一个32位程序

.model flat,stdcall         ;选择程序的内存模式(flat),并确定了子程序的调用规范(stdcall

                ;其原因是32Windows服务要求使用stdcall规范

.stack 4096             ;为运行时堆栈保留了4096字节的存储空间,每个程序都必须有

Invoke              ;call好用,会帮你检查参数,参数用‘,’隔开

Invoke expression[ ,arguments ]

 

定义段:

.data .code .stack 100h

指令:

四个组成成分:标号(可选),指令助记符(必须),操作数(通常必须),注释(可选)

  [ label: ] mnemonic [ operands ] [ ;comment ]

汇编器为每个标号分配一个数字地址。可以在一个标号后面定义多个数据项。在下面的例子中,array定义了第一个数字(1024)的位置,其他数字在内存中的位置紧随其后:

  Array DWORD 1024, 2048

  DWORD 4096, 8192

代码标号可以与指令在同一行上,也可以自己独立一行:

L1: mov ax,bx

L2:…………

注释:

单行注释: ;XXXX

块注释(使用COMMENT伪指令和一个用户定义的符号开始,到再次出现用户定义符号)

COMMENT !

    This line is a comment.

    This line is also a comment.

  !

空指令:NOP

示例:

.386

.model flat,stdcall                   ;32位程序总是使用平面(flat)模式

.stack 4096

ExitProcess PROTO, dwExitCode:DWORD       ;声明了ExitProcess函数的原型

                          ;它是一个标准的windows服务

.code

Main PROC

  Mov eax, 5

  Add eax, 6

 

  INVOKE ExitProcess, 0

  Main ENDP

END Main

注:使用RadASM编译并连接时,需加上 Includelib Kernel32.lib

否则会报错

  Value1 BYTE ‘A’

  Value2 BYTE 0

  Value3 DB 255

  Value4 SBYTE -128

  Value5 DB +127

  Value6 BYTE ? ;问号使得变量未初始化,这意味着在运行时分配数值到该变量

 

多初始值:

  List   BYTE 10,20,30,40

 

 

定义字符串:

;最常见的字符串类型是用一个空字节(值为0)作为结束标记,称为以空字节结束的字符串

  Greeting1 BYTE “Good afternoon”, 0

  Greeting2 BYTE “Good night”,0

  Greeting3 BYTE “welcome to the Encryption Demo program ”

  BYTE “created by Kip Irvine.”, 0dh,0ah

  BYTE “If you wish to modify this program, please ”

  BYTE “send me a copy.”,0dh,0ah,0

十六进制代码0dh0ah也被称为CR/LF(回车换行符)或行结束字符。在编写标准输出时,它们将光标移动到当前行的下一行的左侧。

行连续字符(\)把两个源代码行连接成一条语句,他必须是一行的最后一个字符。下面的语句是等价的:

  Greeting1 BYTE “welcome to the Encryption Demo program ”

  Greeting1 \

  BYTE “welcome to the Encryption Demo program ”

 

DUP操作符:

DUP操作符使用一个整数表达式作为计算器,为多个数据项分配存储空间。在为字符串或数组分配存储空间时,这个操作符非常有用,它可以使用初始化或非初始化数据。

  BYTE 20 DUP(0) ;20个字节,值都为0

  BYTE 20 DUP(?) ;20个字节,非初始化

  BYTE  4 DUP(“STACK”) ;20个字节

 

WORDSWORD----16位整数

  Word1 WORD 65535 ;最大无符号数

  Word2 SWORD -32768 ;最小有符号数

  Word3 WORD ? ;未初始化,无符号

  Word4 DW 65535

 

16位字数组:

通过列举元素或使用DUP操作符来创建字数组。下面的数组包含了一组数值:

  myList DW 1,2,3,4,5

  Array DW 5 DUP(?) ; 5个数值,未初始化

 

 

定义DWORDSDWORD(双字32位)数据:

  Val1 DD 12345678h

  Val2 DD -2147483648

  DWORD还可以用于声名一种变量,这种变量包含的是另一个变量的32位偏移量。如下所示,pVal包含的就是val3的偏移量:

  pVal DWORD val3

32位双字数组:

  myList DWORD 1,2,3,4,5

 

定义浮点类型:

  REAL4 4字节单精度浮点变量 ; DD

  REAL8 8字节双精度数值 ; DQ

  REAL10 10字节扩展精度数值 ; DT

 

  rVal1 REAL4 -1.2

  rVal2 REAL8 3.2E-260

  rVal3 REAL10 4.6E+4096

  ShortArray REAL4 20 DUP(0.0)

 

变量加法程序:

.386

.model flat, stdcall

.stack 4096

ExitProcess PROTO, dwExitCode:DWORD

 

.data

Firstval DD 20002000h

Secondval DD 11111111h

Thirdval DD 22222222h

Sum DD 0

 

.code

Main PROC

  Mov eax,Firstval

  Add eax,Secondval

  Add eax,Thirdval

  Mov Sum,eax

 

  INVOKE ExitProcess, 0

Main ENDP

END Main

 

X86处理器在内存中按小端顺序(从低到高)存放和检索数据。最低有效字节存放在分配给该数据的第一个内存地址中,剩余字节存放在随后的连续内存位置中。

汇编器允许在程序中进行代码和数据的来回切换,但会使得程序变得难以阅读。

等号伪指令(符号常量):

  Name = expression

通常,表达式是一个32位的整数值。当程序进行汇编,在汇编器的预处理阶段,所有出现的name都会被替换成expression

使用等号伪指令来获得更好的编码风格

  Esc_key = 27

  Mov al, Esc_key ;好的风格

  --------------------------

  Mov al, 27 ;不好的风格

重定义:

  COUNT = 5

  Mov al, COUNT

  COUNT = 10

  Mov al, COUNT

  COUNT = 100

  Mov al, COUNT

 

当前地址计数器:

当前地址计数器表示为 $

  selfPtr DWORD $

 

计算数组大小(必须紧跟其后):

  List BYTE 10,20,30,40

  ListSize = ( $ - list )  /  1

 

  List WORD 1000h,2000h,3000h,4000h

  ListSize = ( $ - list )  /  2

 

  List DWORD 10000000h,20000000h,30000000h,40000000h

  ListSize = ( $ - list )  /  4

 

EQU伪指令:

EQU伪指令把一个符号名称与一个整数表达式或任意文本连接起来

  Name EQU expression

  Name EQU symbol

  Name EQU <text>

第一种格式中,expression必须是有效整数表达式(每个表达式的计算结果必须是一个整数)

第二种格式中,symbol是一个已存在的符号名称,已经用=EQU定义过了。

第三种格式中,任何文本都可以出现在<>内。

当汇编器在程序后面遇到Name时,他就用整数值或文本来代替符号。

  PI EQU <3.1416>

  PressKey EQU <”Press any key to continue...”,0>

 

与等号伪指令不同,在同一源代码文件中,用EQU定义的符号不能被重新定义。这个限制可以防止现有符号在无意中被赋予新值。

 

TEXTEQU伪指令:

TEXTEQU伪指令,类似于EQU,创建了文本宏(text macro)。

  Name TEXTEQU <text>

  Name TEXTEQU textmacro

  Name TEXTEQU %constExpr

例如,变量prompt1使用了文本红continueMsg

  continueMsg TEXTEQU <”Do you wish to continue (Y/N)?”>

  .data

  Prompt1 BYTE continueMsg

文本宏可以相互构建,如下例:

  rowSize =  5

  count TEXTEQU %(rowSize * 2)

  move TEXTEQU <mov>

  setupAL TEXTEQU <move  al, count>

因此,语句setupAL就会被会变为 mov  al, 10

TEXTEQU定义的符号随时可以被重新定义。

 

64位编程:

ExitProcess PROTO

 

.data

Sum DD 0

.code

Main  PROC

  Mov eax, 5

  Add eax, 6

  Mov sum, eax

 

  Mov ecx, 0

  Call ExitProcess

Main  ENDP

END

32位不同的是:

没有 .386

.model flat, stdcall

. stack 4096

64位程序中,使用PROTO关键字的语句不带参数:

32: ExitProcess PROTO, dwExitCode:DWORD

64: ExitProcess PROTO

 

64MASM不支持INVOKE伪指令

END伪指令没有指定程序入口点,而32位程序则指定了

 

 

翻译 朗读 复制 正在查询,请稍候…… 重试 朗读 复制 复制 朗读 复制 via 谷歌翻译(国内)

posted @ 2020-04-19 09:39  seccold  阅读(552)  评论(0)    收藏  举报