指令中的符号(#,$,%)
在指令中,我们最常见到的符号有#和$。
这其中的"#"符号是告诉汇编程序,这个符号后面的数值为一个立即数,而不是一个偏移值或一个地址。立即数可以理解为"单纯的一个数值"。我们会在后面通过一些实例来更详细说明什么叫立即数。
而$符号是告诉汇编程序,这个符号后的数值为一个16进制数值;如果符号为%,那它后面的数值为一个2进制的数值;如果没有任何符号,它后面的数为一个10进制数值。
我们来看以下几条代码:
move.b #%00010000,d0
move.b #16,d0
move.b #$10,d0
上面这几条指令的意思是一样的,第一行是2进制数值(%),第二行是10进制数值,最后一行是16进制数值($)
我们可以用计算器来查看各个进制之间的换算
我们回到立即数的问题,我们用两行代码来进行测试,更详细地说明什么是立即数
move.b #$10,d0
*这条指令将会把$10这个数值置入到d0寄存器。
move.b $10,d0
*这条指令将会读取地址$10处的字节,然后把它复制到d0寄存器,如果$10位置的值是88,那么d0寄存器的值也会在这条指令执行后变成88。
我们先来测试第一个指令:
*-----------------------------------------------------------
* Title :
* Written by :
* Date :
* Description:
*-----------------------------------------------------------
ORG $1000
START: ; first instruction of program
* Put program code here
move.b #$10,d0
SIMHALT ; halt simulator
* Put variables and constants here
END START ; last line of source
运行后的结果
*-----------------------------------------------------------
* Title :
* Written by :
* Date :
* Description:
*-----------------------------------------------------------
ORG $1000
START: ; first instruction of program
* Put program code here
move.b #$88,$10 *把$88立即数 置入 地址$10
move.b $10,d0 *把$10地址的值 置入 D0寄存器
SIMHALT ; halt simulator
* Put variables and constants here
END START ; last line of source
运行结果:
奇数地址
至些为止,我们尝试了几个指令的执行,在了解更多的指令之前,我们还需要了解一些比较重要的东西。
我们刚刚测试了从内存中读写的例子:
move.b $10,d0
我们可以在操作长度为单字节的情况下,用奇数地址对内存进行读写,比如:
move.b $11,d0
但很重要的是,我们如果在操作双字节或四字节长度时,不能对奇数地址进行读写,比如下面的代码是一个非法的例子:
move.w $11,d0
move.l $11,d0
该规则对所有指令适用,所以,我们需要保证,需要从奇数地址读写数据时,只能读写单字节长度的数据。
标签
标签由字母、数字和下划线组成,必须以下划线、@符号或字母开头。标签后面可以有可选的冒号。标准汇编语言约定使用以“@”开头的标签作为过程或函数的本地标签。与其他类型的标识符一样,标签不区分大小写。
标签可以在任何指令的前面,我们可以在很多指令中使用标签功能,最常见的是jmp之类的跳转指令,比如:
ORG $100
START:
move.w d0, d1
add.w d1, d1
add.w d1, d0
jmp label
add.w d2, d3
asr.w #$04, d0
label:
move.w d0, d2
END START
我们可以测试这段代码,我们可以看到代码中的label:就是一个标签,当执行jmp label时,程序会把label:标签所在的地址传递到PC寄存器。
ORG $100
START:
movea.l #label,a0
label:
move.w d0,d2
END START
在这段代码中,当执行movea.l #label,a0时,程序会把label:向在的地址传递到a0寄存器。
ORG指令
该指令声明了在内存中加载后续指令和数据的位置。
ORG $100
START:
move.b d0,d1
ORG $200
move.b d2,d3
END START
我们可以看到,第一句move指令被保存在了地址$100,第二句move指令被保存在了地址$200。
dc指令
定义常量。DC指令将指定的数据或字符串放置在指令流中。也可以把字符定义到指令流中。
我们可以测试:
ORG $100
START:
dc.b 'abcd'
dc.b $01 , $02 , $03 , $04
dc.w $1010 , $1234
dc.l $30303030
END START
我们可以看到,该指令会把操作数直接置入到指令流中,当操作数为字符串时,会把该字符的ASCII码对应的值置入指令流。
ds指令
该指令会声明一段空白的内存空间。声明空间的大小由操作数和操作长度决定。
ORG $100
START:
ds.b $10
dc.l $00010203 , $04050607, $08090a0b, $0c0d0e0f
ds.w $10
dc.l $00010203 , $04050607, $08090a0b, $0c0d0e0f
ds.l $10
dc.l $00010203 , $04050607, $08090a0b, $0c0d0e0f
END START
我们可以看到,三个ds的指令虽然操作数都相同,但操作长度不同,所以,声明的空间大小也不同。
nop指令
该指令在程序中不起任何作用,我们可以把他想象为一个空指令,在逆向研究中,我们常常会用到该指令来对程序进行一些测试。
nop指令固定是占用2个字节的存储空间,它经过编译器编译后生成的机器码为"4E71"。这个机器码我们会经常用到。