gnu arm asm匯編

.global/.def/.ref Identify Global Symbols
Syntax .global symbol1[, ... , symboln]
.def symbol1[, ... , symboln]
.ref symbol1[, ... , symboln]
Description -----------Three directives identify global symbols that are defined externally or can be referenced externally:
引用文檔來自:ARM Assembly Language Tools v17.6.0.STS User's Guide

這三個指令都可以定義一個全局的符號,可以被其他的程序使用,

The .def directive identifies a symbol that is defined in the current module and can be
accessed by other files. The assembler places this symbol in the symbol table.

.def在當前module定義,可以被其他文件訪問,這個符號也會被存在symbol table里面

The .ref directive identifies a symbol that is used in the current module but is defined in another module. The linker resolves this symbol's definition at link time.

.ref指令說明這個符號在當前module中使用,但是在別的module中定義,鏈接器最終會在鏈接的時候找到其定義

The .global directive acts as a .ref or a .def, as needed.

A global symbol is defined in the same manner as any other symbol; that is, it appears
as a label or is defined by the .set, .equ, .bss, or .usect directive. If a global symbol is
defined more than once, the linker issues a multiple-definition error. (The assembler can
provide a similar multiple-definition error for local symbols.)

如果一個global symbol被多次定義,assembler會提醒一個多次定義的錯誤,.ref指令不管modules用不用
這個symbol,都會在符號表里創(chuàng)建一個entry,.global的話只會在用到這個symbol的時候才創(chuàng)建.

The .ref directive always creates a symbol table entry for a symbol, whether the module uses the symbol or not; .global, however, creates an entry only if the module actually uses the symbol.

.ref不管用不用到,符號表里都有一個符號的entry,global定義的則只會在使用到的時候才會創(chuàng)建一個entry

A symbol can be declared global for either of two reasons:

出于以下兩種原因聲明一個.global符號

? If the symbol is not defined in the current module (which includes macro, copy, and
include files), the .global or .ref directive tells the assembler that the symbol is defined in an external module. This prevents the assembler from issuing an unresolved reference error. At link time, the linker looks for the symbol's definition in other modules.

如果symbol沒有定義在當前文件,(包括macro, copy, and include files)
.global和.ref告訴assembler symbol定義在別的module,防止assembler產(chǎn)生一個引用錯誤,鏈接的時候,linker會在別的module查找該符號的定義

? If the symbol is defined in the current module, the .global or .def directive declares
that the symbol and its definition can be used externally by other modules. These
types of references are resolved at link time.

如果symbol定義在了當前文件,通過上述兩個命令就可以在其他文件中使用這個symbol
  • 以下是一個例子

The file1.lst and file3.lst files are equivalent. Both files define the symbol INIT and make it available to other modules; both files use the external symbols X, Y, and Z. Also, file1.lst uses the .global directive to identify these global symbols; file3.lst uses .ref and .def to identify the symbols.

1,3定義了一個 external symbol INIT,都使用external symbol X,Y,Z

The file2.lst and file4.lst files are equivalent. Both files define the symbols X, Y, and Z and make them available to other modules; both files use the external symbol INIT. Also, file2.lst uses the .global directive to identify these global symbols; file4.lst uses .ref and.def to identify the symbols.

2,4定義了external symbol X,Y,Z

file1.lst

file1

file2.lst

file2

file3.lst

file3

file4.lst

file4

以下是在linux主機下的一個實際的例子
1.S

.global X, Y, Z
    ADD R0, R0, #0x56
.word X
.end

2.S

.global X, Y, Z
#.extern X, Y, Z
    .set X, 1
    .set Y, 2
    .set Z, 3

.end

Makefile

objs := 1.o 2.o
all:$(objs)
    arm-linux-ld -o exam_elf $^
    arm-linux-objdump -D -m arm exam_elf > exam.dis
    
%.o:%.S
    arm-linux-gcc -c -o $@ $<

clean:
    rm *.o *.dis exam*

.global相當于c 語言里面聲明一個變量為全局變量,有點類似于c里面的extern,1.Sl里面的.global可以去掉,make的時候也不會報錯
反匯編出來的文件在add指令后的地址確實存放的是0x1


exam_elf:     file format elf32-littlearm

Disassembly of section .text:

00008074 <.text>:
    8074:   e2800056    add r0, r0, #86 ; 0x56
    8078:   00000001    andeq   r0, r0, r1

但是2.S里面的.global不能取消,雖然能夠通過編譯,但是鏈接的時候,提示找不到X這個symbol

arm-linux-gcc -c -o 2.o 2.S
2.S:7:5: warning: no newline at end of file
arm-linux-ld -o exam_elf 1.o 2.o
arm-linux-ld: warning: cannot find entry symbol _start; defaulting to 00008074
1.o(.text+0x4): In function `$a':
: undefined reference to `X'
make: *** [all] Error 1

_start這個symbol不加上global的時候,make的時候會有一個警告

arm-linux-ld: warning: cannot find entry symbol _start; defaulting to 00008074
  • <armasm_Assembler User Guide version 6.7 pdf>
    MCR{cond} coproc, #opcode1, Rt, CRn, CRm{, #opcode2}
    MCR: Move to Coprocessor from ARM Register,把寄存器的值放到Coprocessor
    MRC:Move to ARM Register from Coprocessor,從Coprocessor讀到寄存器里面去
    coproc:要訪問的協(xié)處理器寄存器號:pn,例如p15.
    opcode1
    is a 3-bit coprocessor-specific opcode.這個一般在協(xié)處理器文檔有規(guī)定.參考哪個文檔選取值
    opcode2
    is an optional 3-bit coprocessor-specific opcode這個是可選的
    Rt
    is an ARM source register. Rt must not be PC. r0,r1等等寄存器了
    CRn, CRm
    are coprocessor registers. 例如cp15寄存器下的0號,1號寄存器.
    The opcode_1, opcode_2, and CRm fields should be zero, except when the values specified are used to select the desired operations

0號寄存器有兩個,肯定有不同的訪問方法,取決于opcode_2的值
CRn表示要訪問p15寄存器里的哪一個寄存器
注意事項:

The opcode_1, opcode_2, and CRm fields should be zero, except when the values specified
are used to select the desired operations, in all instructions that access CP15. Using
other values results in unpredictable behavior

Register 0, ID code register,32bit,,opcode_2設置成任何值(除了1)表示讀取device ID

MRC p15,0,Rd,c0,c0,0 ; returns ID register

This is a read-only register that returns a 32-bit device ID code.
You can access the ID code register by reading CP15 register 0 with the opcode_2 field
set to any value other than 1 (the CRm field should be zero when reading).
Register 0, ID code

以下摘自arm 體系架構(gòu)手冊
A2.10.5 Configuration and control

MCR{<cond>} p14, 7, <Rd>, CRn, CRm{, opcode_2}*
MRC{<cond>} p14, 7, <Rd>, CRn, CRm{, opcode_2}*
*opcode_2 can be omitted if opcode_2 == 0

ARM Compiler v5.06 for μVision armasm User Guide
?10.41 LDM
格式:LDM{<cond>}{<type>} <Rn>{!},<regs>{^};
功能:從一片連續(xù)的內(nèi)存單元讀取數(shù)據(jù)到各個寄存器中,內(nèi)存單元的起始地址為基址寄存器Rn的值,各個寄存器由寄存

LDMIA R1!,{R2-R7,R12} ;將R1指向的若干個存儲單元中的數(shù)據(jù)讀寫到R2~R7、R12中,然后R1自加4 *寄存器的個數(shù), 
        器列表regs表示。 
  該指令一般用于多個寄存器數(shù)據(jù)的出棧。 
  type字段種類: 
      IA:每次傳送后地址加1。 
      IB:每次傳送前地址加1。 
      DA:每次傳送后地址減1。 
      DB:每次傳送前地址減1。 
      FD:滿遞減堆棧。 
      ED:空遞減堆棧。 
      FA:滿遞增堆棧。 
      EA:空遞增堆棧。 
  堆棧尋址的命令LDMFA/STMFA、LDMEA/STMEA、LDMFD/STMFD、LDMED/STMED。
  LDM和STM表示多寄存器尋址,即一次可以傳送多個寄存器值。
  LDM:一次裝載多個,這里用來出棧。
  STM:一次存儲多個,這里用來入棧。
 STMIA R1!,{R2-R7,R12} ;將寄存器R2~R7、R12的值保存到R1指向的存儲單元中,然后R1自加4 *寄存器的個數(shù)
  F/E表示指針指向的位置
  F:full滿堆棧,表示堆棧指針指向最后一個入棧的有效數(shù)據(jù)項。
  E:empty空堆棧,表示堆棧指針指向下一個要放入的空地址。
  A/D表示堆棧的生長方式
  A:堆棧向高地址生長,即遞增堆棧。
  D:堆棧向低地址生長,即遞減堆棧。

注意:有一個約定,編號低的寄存器在存儲數(shù)據(jù)或者加載數(shù)據(jù)時對應于存儲器的低地址。
FD、ED、FA和EA指定是滿棧還是空棧,是升序棧還是降序棧,用于堆棧尋址。
一個滿棧的棧指針指向上次寫的最后一個數(shù)據(jù)單元.
空棧的棧指針指向第一個空閑單元。
一個降序棧是在內(nèi)存中反向增長而升序棧在內(nèi)存中正向增長。
{!}:若選用了此后綴,則當指令執(zhí)行完畢后,將最后的地址寫入基址寄存器。
{^}:當regs中不包含PC時,該后綴用于指示指令所用的寄存器為用戶模式下的寄存器,
否則指示指令執(zhí)行時,將寄存器SPSR的值復制到CPSR中。

//注意:有一個約定,編號低的寄存器在存儲數(shù)據(jù)或者加載數(shù)據(jù)時對應于存儲器的低地址
    ldr sp, =0x1000---存放的是0x1,0x2
    LDMIA SP!,{r2-r3}--執(zhí)行完之后r2 = 0x1,r3 = 0x2,去掉感嘆號!,sp寄存器的值不會發(fā)生改變,仍然是r2 = 0x1,r3 = 0x2
0x1000處內(nèi)存數(shù)據(jù)
上述代碼執(zhí)行完的效果

再來看另外一個例子

ldr sp, =0x1000,0xffc存放0x1,0x1000存放0x2
LDMDA SP,{R2-r3}  r2 = 0x1,r3 = 0x2
內(nèi)存截圖
執(zhí)行完之后效果
__lookup_processor_type:
    adr r3, 3f
    ldmda   r3, {r5 - r7}
    sub r3, r3, r7          @ get offset between virt&phys
    add r5, r5, r3          @ convert virt addresses to
    add r6, r6, r3          @ physical address space
1:  ldmia   r5, {r3, r4}            @ value, mask
    and r4, r4, r9          @ mask wanted bits
    teq r3, r4
    beq 2f
    add r5, r5, #PROC_INFO_SZ       @ sizeof(proc_info_list)
    cmp r5, r6
    blo 1b
    mov r5, #0              @ unknown processor
2:  mov pc, lr
    
    .long   __proc_info_begin
    .long   __proc_info_end
3:  .long   .
    .long   __arch_info_begin
    .long   __arch_info_end

代碼的地址是從低地址一直排到高地址的.
所以
r7 = . r6 = __proc_info_end, r5 = __proc_info_begin標號都是絕對地址

關于arm寄存器的介紹

寄存器名字
Reg# APCS 意義
R0 a1 工作寄存器
R1 a2 "
R2 a3 "
R3 a4 "
R4 v1 必須保護
R5 v2 "
R6 v3 "
R7 v4 "
R8 v5 "
R9 v6 "
R10 sl 棧限制
R11 fp 楨指針
R12 ip 內(nèi)部過程調(diào)用寄存器
R13 sp 棧指針
R14 lr 連接寄存器
R15 pc 程序計數(shù)器
The following register names are predeclared:

r0-r15 andR0-R15
a1-a4 (argument, result, or scratch registers, synonyms for r0 to r3)
v1-v8 (variable registers, r4 to r11)
sb andSB (static base, r9)
ip andIP (intra-procedure-call scratch register, r12)
sp andSP (stack pointer, r13)
lr andLR (link register, r14)
pc andPC (program counter, r15).

CPSR寄存器介紹


格式(參考文檔

  1. ARM Architecture Reference Manual
    A2.5 Program status registers
  2. CPU三星S3C2440A芯片手冊
    THE PROGRAM STATUS REGISTERS
    )
詳細的指令解釋可參考:ARM Architecture Reference Manual.pdf
MSR 通用寄存器到程序狀態(tài)寄存器的數(shù)據(jù)傳送指令 ,mrs是相反的作用.
      格式:MSR{<cond>} CPSR/SPSR_<field>,<op1>; 
      功能:用于將寄存器Rd的值傳送到程序狀態(tài)寄存器中。 
      <field>:用來設置狀態(tài)寄存器中需要操作的位。 這些域的介紹參看
ARM Architecture Reference Manual.pdf
  A3.10 Status register access instructions
               
32位的狀態(tài)寄存器可以分為4個域: 
               位[31:24]為條件標志位域,用f表示。 
               位[23:16]為狀態(tài)位域,用s表示。 
               位[15:8]為擴展位域,用x表示。 
               位[7:0]為控制位域,用c表示。 
      例:
          MSR CPSR_f,R0 ;用R0的值修改CPSR的條件標志域 
          MSR CPSR_fsxc,#5; CPSR的值修改為5 

實際運用的例子:
  msr cpsr_c, #0xd2   參看The mode bits那張圖
  ldr sp, =0x31000000

  msr cpsr_c, #0xdf  
  ldr sp, =0x34000000

關于arm寄存器的介紹

寄存器名字
Reg# APCS 意義
R0 a1 工作寄存器
R1 a2 "
R2 a3 "
R3 a4 "
R4 v1 必須保護
R5 v2 "
R6 v3 "
R7 v4 "
R8 v5 "
R9 v6 "
R10 sl 棧限制
R11 fp 楨指針
R12 ip 內(nèi)部過程調(diào)用寄存器
R13 sp 棧指針
R14 lr 連接寄存器
R15 pc 程序計數(shù)器
The following register names are predeclared:

r0-r15 andR0-R15
a1-a4 (argument, result, or scratch registers, synonyms for r0 to r3)
v1-v8 (variable registers, r4 to r11)
sb andSB (static base, r9)
ip andIP (intra-procedure-call scratch register, r12)
sp andSP (stack pointer, r13)
lr andLR (link register, r14)
pc andPC (program counter, r15).

CPSR寄存器介紹


格式(參考文檔

  1. ARM Architecture Reference Manual
    A2.5 Program status registers
  2. CPU三星S3C2440A芯片手冊
    THE PROGRAM STATUS REGISTERS
    )
ARM Architecture Reference Manual
CPU三星S3C2440A芯片手冊

A2.5.8 The T and J bits的參考


A2.5.8 The T and J bits

ARM Architecture Reference Manual.pdf
A2.5.6 The interrupt disable bits


中斷bit的參考

mode bit各個對應值的相關參考,其他各個位均可參考ARM Architecture Reference Manual,這里就不一一列出來.

The mode bits

bic指令語法
  BIC{<cond>}{S} <Rd>, <Rn>, <shifter_operand>
Rd = Rn AND NOT shifter_operand
bit 位清除指令 
      格式:BIC{<cond>}{S} <Rd>,<Rn>,<op2>; 
      功能:Rd=Rn AND (!op2) 用于清除寄存器Rn中的某些位,并把結(jié)果存放到目的寄存器Rd中
      例: 
        BIC R0,R0,#5 ;R0中第0位和第2位清0,其余位不變

ORR 邏輯或指令 
      格式:ORR{<cond>}{S} <Rd>,<Rn>,<op2>; 
      功能:Rd=Rn OR op2 一般用于設置Rn的特定幾位。
      例: 
        ORR R0,R0,#5  ;R0的第0位和第2位設置為1,其余位不變 

adr指令參考(adr是偽指令,反匯編的時候會被替換成別的指令)

ARM Developer Suite Assembler Guide
?4.9 ARM pseudo-instructions
??4.9.1 ADR ARM pseudo-instruction

ARM? Compiler v5.06 for μVision? armasm User Guide
?10.11 ADR (PC-relative)
?10.12 ADR (register-relative)

adr指令是位置無關的,取得_start標號的地址,依賴于pc的值加上偏移,如果pc是0.就是0+offset,如果是0x30000000就是0x30000000 + 偏移


adr指令反匯編
7.5 Register-relative and PC-relative expressions
In ARM code, the value of the PC is the address of the current instruction plus 8 bytes.

ADR (PC-relative)
Generate a PC-relative address in the destination register, for a label in the current area.
----- label計算其相對于PC的地址,存入rd寄存器-----
Syntax

ADR{cond}{.W} Rd,label

where:
cond
is an optional condition code.

.W
is an optional instruction width specifier.

Rd
is the destination register to load.

label
is a PC-relative expression.
label must be within a limited distance of the current instruction.

Usage
ADR produces position-independent code, because the assembler generates an instruction that adds or subtracts a value to the PC.
------adr指令是位置無關指令------
Use the ADRL pseudo-instruction to assemble a wider range of effective addresses.
------ ADRL可以尋址更遠------
label must evaluate to an address in the same assembler area as the ADR instruction.
If you use ADR to generate a target for a BX or BLX instruction, it is your responsibility to set the Thumb bit (bit 0) of the address if the target contains Thumb instructions

arm mode pc = current address + 8bytes

str指令
STR{<c>}{<q>} <Rt>, [<Rn> {, #+/-<imm>}] Offset: index==TRUE, wback==FALSE
STR{<c>}{<q>} <Rt>, [<Rn>, #+/-<imm>]! Pre-indexed: index==TRUE, wback==TRUE
STR{<c>}{<q>} <Rt>, [<Rn>], #+/-<imm> Post-indexed: index==FALSE, wback==TRUE

ldr指令
LDR(或LDRB、LDRBT、LDRH、LDRSB、LDRSH、LDRT、STR、STRB、STRBT、STRH、STRT) <Rd>,<addr>;

LDR Rd,[Rn]             ;把內(nèi)存中地址為Rn的字數(shù)據(jù)裝入寄存器Rd中 
LDR Rd,[Rn,Rm]          ;將內(nèi)存中地址為Rn+Rm的字數(shù)據(jù)裝入寄存器Rd中 
LDR Rd,[Rn,#index]     ;將內(nèi)存中地址為Rn+index的字數(shù)據(jù)裝入Rd中 
            LDR Rd,[Rn,Rm,LSL#5]   ;將內(nèi)存中地址為Rn+Rm×32的字數(shù)據(jù)裝入Rd 
            LDR Rd,[Rn,Rm]!         ;將內(nèi)存中地址為Rn+Rm的字數(shù)據(jù)裝入Rd,并將新地址Rn+Rm寫入Rn 
            LDR Rd,[Rn,#index]!    ;將內(nèi)存中地址為Rn+index的字數(shù)據(jù)裝入Rd,并將新地址Rn+index寫入Rn 
            LDR Rd,[Rn,Rm,LSL#5]! ;將內(nèi)存中地址為Rn+Rm×32的字數(shù)據(jù)裝入Rd,并將新地址Rn+Rm×32寫入Rn 
            LDR Rd,[Rn],Rm          ;將內(nèi)存中地址為Rn的字數(shù)據(jù)裝入寄存器Rd,并將新地址Rn+Rm寫入Rn 
            LDR Rd,[Rn],#index     ;將內(nèi)存中地址為Rn的字數(shù)據(jù)裝入寄存器Rd,并將新地址Rn+index寫入Rn 
            LDR Rd,[Rn],Rm,LSL#5   ;將內(nèi)存中地址為Rn的字數(shù)據(jù)裝入寄存器Rd,并將新地址Rn+Rm×32寫入Rn 

STR指令
STR(或STR、STRB、STRBT、STRH、STRT) <Rd>,<addr>;
功能:將寄存器數(shù)據(jù)寫入到內(nèi)存中
尋址方式:Rn:基址寄存器。Rm:變址寄存器。Index:偏移量,12位的無符號數(shù)。

STR Rd,[Rn]             ;將寄存器Rd中的字數(shù)據(jù)寫入到內(nèi)存中地址為Rn內(nèi)存中
STR Rd,[Rn,Rm]          ;將寄存器Rd中的字數(shù)據(jù)寫入到內(nèi)存中地址為Rn+Rm的內(nèi)存中
STR Rd,[Rn,#index]     ;將寄存器Rd中的字數(shù)據(jù)寫入到內(nèi)存中地址為Rn+index內(nèi)存中
STR Rd,[Rn,Rm,LSL#5]   ;將寄存器Rd中的字數(shù)據(jù)寫入到內(nèi)存中地址為Rn+Rm×32內(nèi)存中
STR Rd,[Rn,Rm]!         ;將寄存器Rd中的字數(shù)據(jù)寫入到內(nèi)存中地址為Rn+Rm的內(nèi)存中
STR Rd,[Rn,#index]!    ;將寄存器Rd中的字數(shù)據(jù)寫入到內(nèi)存中地址為Rn+index的內(nèi)存中,并將新地址Rn+index寫入Rn 
STR Rd,[Rn,Rm,LSL#5]! ;將寄存器Rd中的字數(shù)據(jù)寫入到內(nèi)存中地址為Rn+Rm×32的內(nèi)存中,并將新地址Rn+Rm×32寫入Rn 
STR Rd,[Rn],Rm          ;將寄存器Rd中的字數(shù)據(jù)寫入到內(nèi)存中地址為Rn的內(nèi)存中,并將新地址Rn+Rm寫入Rn 
STR Rd,[Rn],#index     ;將寄存器Rd中的字數(shù)據(jù)寫入到內(nèi)存中地址為Rn的內(nèi)存中,并將新地址Rn+index寫入Rn 
STR Rd,[Rn],Rm,LSL#5   ;將寄存器Rd中的字數(shù)據(jù)寫入到內(nèi)存中地址為Rn的內(nèi)存中,并將新地址Rn+Rm×32寫入Rn 
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容