例如:
MOV AH, 80H ADD AX, 1234H MOV ECX, 123456H
MOV B1, 12H MOV W1, 3456H ADD D1, 32123456H
其中:B1、W1和D1分別是位元組、字和雙字單元。
以上指令中的第二運算元(源運算元)都是立即數,在彙編語言中,規定:立即數不能作為指令中的第一運算元(目的運算元)。該規定與高級語言中“賦值語句的左邊不能是常量”的規定相一致。
立即數定址方式通常用於對通用暫存器或記憶體單元賦初值。
下面以ARM彙編編譯器為例:
立即數方式:每個立即數由一個8位的常數循環右移偶數位得到。其中循環右移的位數由一個4位二進制的兩倍表示。如果立即數記作<immediate>,8位常數記作immed_8,4位的循環右移值記作rotate_imm,則有:
<immediate>=immed_8循環右移(2*rotate_imm)
這樣並不是每一個32位的常數都是合法的立即數,只有能夠通過上面構造方法得到的才是合法的立即數。
下面的常數是合法的立即數:
0xff,0x104,0xff0,0xff00
下面的數不能通過上述構造方法得到,則不是合法的立即數:
0x101,0x102,0xFF1
同時按照上面的構造方法,一個合法的立即數可能有多種編碼方式。如0x3f0是一個合法的立即數,它可以採用下面兩種的編碼方式:
immed_8=0x3f,rotate_imm=0xe或者
immed_8=0xfc,rotate_imm=0xf
轉換為二進制形式如下:
0x3f=0000 0000 0000 0000 0000 0000 0011 1111
0xe=14(十進制) 2*14=28
∴,0x3f循環右移28位得到如下:
0000 0000 0000 0000 0000 0011 1111 0000=0x3f0
immed_8=0xfc,rotate_imm=0xf 的轉換如下:
0xfc=0000 0000 0000 0000 0000 0000 1111 1100
rotate_imm=0xf=15(十進制) 15*2=30
所以0xfc循環右移30位得到如下結果:
0000 0000 0000 0000 0000 0011 1111 0000=0x3f0
可以看出,結果是一樣的!!!
但是,由於這種立即數的構造方法中包含循環移位操作,而循環移位操作會影響CPSR的條件標誌位C。因此,同一個合法的立即數由於採用了不同的編碼方式,將使得某些指令的執行產生不同的結果,這是不能允許的。ARM彙編編譯器按照下面的規則生成立即數的編碼。
1.當立即數數值在0和0xFF範圍時,零immmed_8=<immediate>,rotate_imm=0.、
2.其他情況下,彙編編譯器選擇使rotate_imm數值最小的編碼方式。所以0x3f0的正確表示法是第一種。
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
解釋二:
一條典型的ARM指令語法格式分為如下幾個部分: <opcode> {<cond>} {S} <Rd> ,<Rn>{,<operand2>} 其中,<>內的項是必須的,{}內的項是可選的,如<opcode>是指令助記符,是必須的,而{<cond>}為指令執行條件,是可選的,如果不寫則使用默認條件AL(無條件執行)。 opcode 指令助記符,如LDR,STR 等 cond 執行條件,如EQ,NE 等 S 是否影響CPSR 暫存器的值,書寫時影響CPSR,否則不影響 Rd 目標暫存器 Rn 第一個運算元的暫存器 operand2 第二個運算元
其指令編碼格式如下: 31-28 cond 27-25 001 24-21 opcode 20 S 19-16 Rn 15-12 Rd 11-0 (12位) operand2
對其中的operand2的常數表達式有這樣的規定:“該常數必須對應8位點陣圖,即常數是由一個8位的常數循環右移偶數位得到的。”這句話的意思是說,當用12位第二運算元來表示一個32位立即數時,採用的是將8位數通過移位的方式來實現的,其中12位第二運算元的低八位存放被移位的“基本”數(取值範圍為0到255),而高四位存放的是循環右移的位數,因為是四位二進制數,所以取值範圍位為0到15,而對應的移位位數則為0到30位(因為移動的可能只有31種),也就是說若“移位”數為0,則表示“基本”數不變,若“移位”數為1,則表示將“基本”數在32位數字空間中循環右移2位,若“移位”數為5,則表示將“基本”數在32位數字空間中循環右移10位,若“移位”數為10,則表示將“基本”數在32位數字空間中循環右移20位,依次類推。舉例表示: AND R1,R2,#0xff 當處理器處理這條指令的第二運算元0xff時,因為0xff為8位二進制數,所以處理器就將其直接放進8位“基本”數中,而4位“移位”數則為0. AND R1,R2,#0x104 當處理器處理這條指令的第二運算元0x104時,因為此時0x104已經超過了8位二進制數,所以處理器就要將其“改造”一下,我們先把0x104轉換成二進制0000 0000 0000 0000 0000 0001 0000 0100,我們可以看到,這個數是0000 0000 0000 0000 0000 0000 0100 0001通過循環右移30位得到的,因此改造後的結果是8位“基本”數中存放0100 0001,而“移位”數為15。 AND R1,R2,#0xff000000 當處理器處理這條指令的第二運算元0xff000000時,處理器同樣要對其“改造”,我們先把0xff000000轉換成二進制1111 1111 0000 0000 0000 0000 0000 0000,我們可以看到,這個數是0000 0000 0000 0000 0000 0000 1111 1111通過循環右移8位得到的,因此改造後的結果是8位“基本”數中存放1111 1111,而“移位”數為4。 我想,通過以上的三個例子,就應該明白了8位點陣圖的原理了。但是,有些數並不符合8位點陣圖的原理,這樣的數在進行程式編譯時,系統將會提示出錯,下面再舉幾個違反8位點陣圖的例子:比如0x101,轉換成二進制後位0000 0000 0000 0000 0000 0001 0000 0001,像這個數,無論向右循環幾位,都無法將兩個1同時放到低8位中,因此不符合8位點陣圖;再比如0x102,轉換成二進制後位0000 0000 0000 0000 0000 0001 0000 0010,如果將兩個1同時放到低8位中,即轉換成二進制後為0000 0000 0000 0000 0000 0000 1000 0001,需要將此二進制數向右移31位,這也不符合循環右移偶數位的條件,因此0x012也不符合8位點陣圖;再舉一個0xff1,轉換成二進制後將會有9個1,不可能將其同時放入8位中,因此當然也不符合啦。 通過正反例的比較,可以總結如下:第一,判斷一個數是否符合8位點陣圖的原則,首先看這個數轉換成二進制後1的個數是否不超過8個,如果不超過8個,再看這n個1(n<=8)是否能同時放到8個二進制位中,如果可以放進去,再看這八個二進制位是否可以循環右移偶數位得到起初被判斷的那個數值,如果可以,則此數值即為符合8位點陣圖原理,否則,不符合。第二,用12位的編碼來表示一個任意的32位數是不可能的,只能通過循環右移八位二進制數偶數位來得到一部分32位數,其餘的無法表示的32位數,只有通過其它途徑獲得了,比如0xffffff00,可以通過0x000000ff按位取反得到,因此在以後的編程中,一定要注意用到的第二運算元是否符合8位點陣圖。