前段時(shí)間看arm的匯編,發(fā)現很多有一個(gè)小點(diǎn),但是借來(lái)的書(shū)上的語(yǔ)法卻沒(méi)有,問(wèn)同學(xué)也不知道,于是在網(wǎng)上查了一番才發(fā)現我書(shū)上看到的是arm的標準匯編,而有小點(diǎn)的gnu的匯編,于是將收集到的資料整理后放到這里來(lái)。
GNU匯編語(yǔ)言結構
主要包括三個(gè)常用的段:
data 數據段 聲明帶有初始值的元素
bss 數據段 聲明使用0或者null初始化的元素
text 正文段 包含的指令, 每個(gè)匯編程序都必須包含此段
使用.section 指令定義段, 如:
.section .data
.section .bss
.section .text
起始點(diǎn):
gnu匯編器使用_start標簽表示默認的起始點(diǎn), 此外如果想要匯編內部的標簽能夠被外部程序訪(fǎng)問(wèn),
需要使用.globl 指令, 如:.globl _start
使用通用庫函數時(shí)可以使用:
ld -dynamic-linker /lib/ld-linux.so.2
本文引用地址:http://dyxdggzs.com/article/201611/319125.htm################################################################################################
# 四, 數據傳遞
################################################################################################
1, 數據段
使用.data聲明數據段, 這個(gè)段中聲明的任何數據元素都保留在內存中并可以被匯編程序的指令讀取,
此外還可以使用.rodata聲明只讀的數據段, 在聲明一個(gè)數據元素時(shí), 需要使用標簽和命令:
標簽:用做引用數據元素所使用的標記, 它和c語(yǔ)言的變量很相似, 它對于處理器是沒(méi)有意義的, 它只是用做匯編器試圖訪(fǎng)問(wèn)內存位置時(shí)用做引用指針的一個(gè)位置。
指令:指示匯編器為通過(guò)標簽引用的數據元素保留特定數量的內存, 聲明命令之后必須給出一個(gè)或多個(gè)默認值。
聲明指令:
.ascii 文本字符串
.asciz 以空字符結尾的字符串
.byte 字節值
.double 雙精度浮點(diǎn)值
.float 單精度浮點(diǎn)值
.int 32位整數
.long 32位整數, 和int相同
.octa 16字節整數
.quad 8字節整數
.short 16位整數
.single 單精度浮點(diǎn)數(和float相同)
例子:
output:
.ascii "hello world."
pi:
.float 2.14
聲明可以在一行中定義多個(gè)值, 如:
ages:
.int 20, 10, 30, 40
定義靜態(tài)符號:
使用.equ命令把常量值定義為可以在文本段中使用的符號,如:
.section .data
.equ LINUX_SYS_CALL, 0x80
.section .text
movl $LINUX_SYS_CALL, ?x
2, bss段
和data段不同, 無(wú)需聲明特定的數據類(lèi)型, 只需聲明為所需目的保留的原始內存部分即可。
GNU匯編器使用以下兩個(gè)命令聲明內存區域:
.comm 聲明為未初始化的通用內存區域
.lcomm 聲明為未初始化的本地內存區域
兩種聲明很相似,但.lcomm是為不會(huì )從本地匯編代碼之外進(jìn)行訪(fǎng)問(wèn)的數據保留的, 格式為:
.comm/.lcomm symbol, length
例子:
.section .bss
.lcomm buffer, 1000
該語(yǔ)句把1000字節的內存地址賦予標簽buffer, 在聲明本地通用內存區域的程序之外的函數是不能訪(fǎng)問(wèn)他們的.(不能在.globl命令中使用他們)
在bss段聲明的好處是, 數據不包含在可執行文件中。在數據段中定義數據時(shí), 它必須被包含在可執行程序中, 因為必須使用特定值初始化它。因為不使用數據初始化bss段中聲明的數據區域,所以?xún)却鎱^域被保留在運行時(shí)使用, 并且不必包含在最終的程序中。
3, 傳送數據
move 指令:
格式 movex 源操作數, 目的操作數。 其中x為要傳送數據的長(cháng)度, 取值有:
l 用于32位的長(cháng)字節
w 用于16位的字
b 用于8位的字節值
立即數前面要加一個(gè)$符號, 寄存器前面要加%符號。
8個(gè)通用的寄存器是用于保存數據的最常用的寄存器, 這些寄存器的內容可以傳遞
給其他的任何可用的寄存器。 和通用寄存器不同, 專(zhuān)用寄存器(控制, 調試, 段)
的內容只能傳送給通用寄存器, 或者接收從通用寄存器傳過(guò)來(lái)的內容。
在對標簽進(jìn)行引用時(shí):
例:
.section .data
value:
.int 100
_start:
movl value, ?x
movl $value, ?x
movl ?x, (?i)
movl ?x, 4(?i)
其中:movl value, ?x 只是把標簽value當前引用的內存值傳遞給eax
movl $value, ?x 把標簽value當前引用的內存地址指針傳遞給eax
movl ?x, (?i) 如果edi外面沒(méi)有括號那么這個(gè)指令只是把ebx中的
值加載到edi中, 如果有了括號就表示把ebx中的內容
傳送給edi中包含的內存位置。
movl ?x, 4(?i) 表示把edi中的值放在edi指向的位置之后的4字節內存位置中
movl ?x, -4(?i) 表示把edi中的值放在edi指向的位置之前的4字節內存位置中
cmove 指令(條件轉移):
cmovex 源操作數, 目的操作數. x的取值為:
無(wú)符號數:
a/nbe 大于/不小于或者等于
ae/nb 大于或者等于/不小于
nc 無(wú)進(jìn)位
b/nae 小于/不大于等于
c 進(jìn)位
be/na 小于或等于/不大于
e/z 等于/零
ne/nz 不等于/不為零
p/pe 奇偶校驗/偶校驗
np/po 非奇偶校驗/奇校驗
有符號數:
ge/nl 大于或者等于/不小于
l/nge 小于/不大于或者等于
le/ng 小于或者等于/不大于
o 溢出
no 未溢出
s 帶符號(負)
ns 無(wú)符號(非負)
交換數據:
xchg 在兩個(gè)寄存器之間或者寄存器和內存間交換值
如:
xchg 操作數, 操作數, 要求兩個(gè)操作數必須長(cháng)度相同且不能同時(shí)都是內存位置
其中寄存器可以是32,16,8位的
bswap 反轉一個(gè)32位寄存器的字節順序
如: bswap ?x
xadd 交換兩個(gè)值并把兩個(gè)值只和存儲在目標操作數中
如: xadd 源操作數,目標操作數
其中源操作數必須是寄存器, 目標操作數可以是內存位置也可以是寄存器
其中寄存器可以是32,16,8位的
cmpxchg
cmpxchg source, destination
其中source必須是寄存器, destination可以是內存或者寄存器, 用來(lái)比較
兩者的值, 如果相等,就把源操作數的值加載到目標操作數中, 如果不等就把
目標操作數加載到源操作數中,其中寄存器可以是32,16,8位的, 其中源操作
數是EAX,AX或者AL寄存器中的值
cmpxchg8b 同cmpxchg, 但是它處理8字節值, 同時(shí)它只有一個(gè)操作數
cmpxchg8b destination
其中destination引用一個(gè)內存位置, 其中的8字節值會(huì )與EDX和EAX寄存器中
包含的值(EDX高位寄存器, EAX低位寄存器)進(jìn)行比較, 如果目標值和EDX:EAX
對中的值相等, 就把EDX:EAX對中的64位值傳遞給內存位置, 如果不匹配就把
內存地址中的值加載到EDX:EAX對中
4, 堆棧
ESP 寄存器保存了當前堆棧的起始位置, 當一個(gè)數據壓入棧時(shí), 它就會(huì )自動(dòng)遞減,
反之其自動(dòng)遞增
壓入堆棧操作:
pushx source, x取值為:
l 32位長(cháng)字
w 16位字
彈出堆棧操作:
popx source
其中source必須是16或32位寄存器或者內存位置, 當pop最后一個(gè)元素時(shí)ESP值應該
和以前的相等
5,壓入和彈出所有寄存器
pusha/popa 壓入或者彈出所有16位通用寄存器
pushad/popad 壓入或者彈出所有32位通用寄存器
pushf/popf 壓入或者彈出EFLAGS寄存器的低16位
pushfd/popfd 壓入或者彈出EFLAGS寄存器的全部32位
6,數據地址對齊
gas 匯編器支持.align 命令, 它用于在特定的內存邊界對準定義的數據元素, 在數據段中.align命令緊貼在數據定義的前面
比較:
cmp operend1, operend2
進(jìn)位標志修改指令:
CLC 清空進(jìn)位標志(設置為0)
CMC 對進(jìn)位標志求反(把它改變?yōu)橄喾吹闹?
STC 設置進(jìn)位標志(設置為1)
循環(huán):
loop 循環(huán)直到ECX寄存器為0
loope/loopz 循環(huán)直到ecx寄存器為0 或者沒(méi)有設置ZF標志
loopne/loopnz 循環(huán)直到ecx為0或者設置了ZF標志
指令格式為: loopxx address 注意循環(huán)指令只支持8位偏移地址
另有一個(gè)比較篇的如下:
ARM匯編和Gnu匯編的轉換
將ARM ADS下的匯編碼移植到GCC for ARM編譯器時(shí),有如下規則:
1, 注釋行以"@"或""代替";"
2, GET或INCLUDE => .INCLUDE
如:get option.a => .include "option.a"
3, EQU => .equ
TCLK2 EQU PB25 => .equ TCLK2, PB25
SETA ==> .equ
SETL ==> .equ
BUSWIDTH SETA 16 => .equ BUSWIDTH, 16
4, EXPORT => .global
IMPORT => .extern
GBLL => .global
GBLA => .global
5, DCD => .long
6, IF :DEF: => .IFDEF
ELSE => .ELSE
ENDIF => .ENDIF
:OR: => |
:SHL: => <<
7, END =>.end
NOTE:在被include的頭文件中,如"option.a"中,不再需要.end,否則會(huì )導致主匯編程序結束。
8, 符號定義加":"號
Entry => Entry:
AREA Word, CODE, READONLY ==> .text
AREA Block, DATA, READWRITE ==> .data
CODE32 ==> .arm
CODE16 ==> .thumb
9, MACRO ==> .macro
MEND ==> .endm
開(kāi)始看start.s中的代碼,又一句.balignl 16,0xdeadbeef,不知什么意思,網(wǎng)上搜了一下了解到這條
命令的作用如下:
.balign[wl] abs-expr, abs-expr, abs-expr
增加位置計數器(在當前子段)使它指向規定的存儲邊界。第一個(gè)表達式參數(結果必須是純粹的數字)是必需參數:邊界基準,單位為字節。例如,‘.balign 8’向后移動(dòng)位置計數器直至計數器的值等于8的倍數。如果位置計數器已經(jīng)是8的倍數,則無(wú)需移動(dòng)。第2個(gè)表達式參數(結果必須是純粹的數字)給出填充字節的值,用這個(gè)值填充位置計數器越過(guò)的地方。第2個(gè)參數(和逗點(diǎn))可以省略。如果省略它,填充字節的值通常是0。但在某些系統上,如果本段標識為包含代碼,而填充值被省略,則使用no-op指令填充空白區。第3個(gè)參數的結果也必須是純粹的數字,這個(gè)參數是可選的。如果存在第3個(gè)參數,它代表本對齊命令允許跳過(guò)字節數的最大值。如果完成這個(gè)對齊需要跳過(guò)的字節數比規定的最大值還多,則根本無(wú)法完成對齊。您可以在邊界基準參數后簡(jiǎn)單地使用兩個(gè)逗號,以省略填充值參數(第二參數);如果您在想在適當的時(shí)候,對齊操作自動(dòng)使用no-op指令填充,本方法將非常奏效。.balignw和.balignl是.balign命令的變化形式。.balignw使用2個(gè)字節來(lái)填充空白區。.balignl使用4字節來(lái)填充。例如,.balignw 4,0x368d將地址對齊到4的倍數,如果它跳過(guò)2個(gè)字節,GAS將使用0x368d填充這2個(gè)字節(字節的確切存放位置視處理器的存儲方式而定)。
如果它跳過(guò)1或3個(gè)字節,則填充值不明確。
GNU中的.word的另一種作用
標簽: word 2011-04-13 18:13
不管是ARM的匯編還是GNU的匯編,都有DCD或者.word命令,它是用來(lái)開(kāi)辟一個(gè)字空間。
如:標識1 .word 標識2 它表示將標識2的數據存放在以標識1的地址上去。這個(gè).word和DCD等指令,相當于C語(yǔ)言的指針(如 char * p)。那么在匯編中用以上的代碼聲明的標識1不需要在該文件中用extern的字段來(lái)表明是可以在外部引用的,它是內存空間,可以在每個(gè)文件中使用這個(gè)標識1.而ldr pc,內存地址 它表示將內存地址中的數據送入pc寄存器中去,而ldr pc,=內存地址它表示將內存地址放入pc寄存器中去。
這些是在分析代碼時(shí)候遇到的不明白的地方,經(jīng)過(guò)查找資料的出來(lái)的。
評論