访问ARM Assembler中声明的程序AREA之外的标签

时间:2014-03-27 09:53:10

标签: assembly arm

您好我已经开始从William Pohl关于这个主题的书中学习ARM Assembler(版本4T指令集),并且一直试图解决那里描述的一些小编程问题。但是,对于如何访问存储在程序中标记点但存在于程序的另一个区域中的某些数据,我变得有些困难。代码的缩写示例如下所示:

AREA Main, CODE, READONLY
ENTRY

main
LDR R0, =list_elements
LDR R1, =list_length

... Some more code ...

ALIGN
AREA ListData, DATA, READWRITE

list_length
DCW 0x2

list_data
DCW 0x081, 0x1da

END

问题在于,当我运行此R0并且R1分别加载值0x40000000和0x40000004时。我从内存映射中了解到,0x40000000是用户可写RAM的第一个地址,两者之间的偏移是正确的,但实际数据值位于完全不同的内存位置。有谁知道如何纠正这个?

我查看了文档并遇到了this,特别是示例12.这似乎正是我想要做的,但我的代码执行方式完全不同于我的期望或似乎。我只是错误地使用了说明,还是我还缺少其他东西?任何帮助将不胜感激

1 个答案:

答案 0 :(得分:0)

的start.s

.globl _start
_start:
    b reset

reset:
    mov sp,#0x8000

    ldr r1,=label0
    ldr r0,[r1]
    ldr r1,label1_addr
    ldr r2,[r1]
    bl otherfun
hang: b hang

label1_addr: .word label1

other.s

.globl otherfun
otherfun:
    bx lr

.globl label0
label0: .word 0x1234
.globl label1
label1: .word 0xABCDEF

memmap(链接描述文件)

MEMORY
{
    ram : ORIGIN = 0x8000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > ram
}

生成文件

ARMGNU ?= arm-none-eabi

COPS = -Wall -O2 -nostdlib -nostartfiles -ffreestanding 

all : start.elf

clean :
    rm -f *.o
    rm -f *.elf
    rm -f *.list

start.o : start.s
    $(ARMGNU)-as start.s -o start.o

other.o : other.s
    $(ARMGNU)-as other.s -o other.o

start.elf : memmap start.o other.o
    $(ARMGNU)-ld start.o other.o -T memmap -o start.elf
    $(ARMGNU)-objdump -D start.elf > start.list

输出start.list

start.elf:     file format elf32-littlearm


Disassembly of section .text:

00008000 <_start>:
    8000:   eaffffff    b   8004 <reset>

00008004 <reset>:
    8004:   e3a0d902    mov sp, #32768  ; 0x8000
    8008:   e59f1014    ldr r1, [pc, #20]   ; 8024 <label1_addr+0x4>
    800c:   e5910000    ldr r0, [r1]
    8010:   e59f1008    ldr r1, [pc, #8]    ; 8020 <label1_addr>
    8014:   e5912000    ldr r2, [r1]
    8018:   eb000002    bl  8028 <otherfun>

0000801c <hang>:
    801c:   eafffffe    b   801c <hang>

00008020 <label1_addr>:
    8020:   00008030    andeq   r8, r0, r0, lsr r0
    8024:   0000802c    andeq   r8, r0, ip, lsr #32

00008028 <otherfun>:
    8028:   e12fff1e    bx  lr

0000802c <label0>:
    802c:   00001234    andeq   r1, r0, r4, lsr r2

00008030 <label1>:
    8030:   00abcdef    adceq   ip, fp, pc, ror #27

所以这个

 ldr r1,=label0

表示我想将label0的地址加载到r1中,但由于我们无法在汇编时解析label0,因此链接器必须在以后填写地址,汇编器必须在.text中保留一个内存位置并生成一个pc相对负载。它做的。什么是最终地址0x8020是汇编程序将地址保持为label0 for start.o

的地方

如果你想明确控制那个单词在.text中的位置,而不是让汇编程序试图找到一个地方,那么你就可以使用这样的代码

    ldr r1,label1_addr
...
label1_addr: .word label1

label1_addr可以被认为是一个局部变量,该指令被解析为pc相对加载,但你可以控制label1_addr在代码中的位置。

label1和label0只是标签,这意味着它们只是地址所以在label1_addr行的末尾你不要说= label1你在这里说label1,我知道这很令人困惑。

我特意将label0和label1全局地址保存在一个单独组装的对象中,以强制它们在外部并由链接器解析。这正是链接器在二进制文件中放置start.o然后是other.o所发生的事情,因为这是它们在命令行上的顺序,并且链接器脚本没有干扰该顺序。所以我们看到start.o代码然后是other.o代码,label0和label1的地址被解析为start.s的汇编设置的位置。

显然,我使用的是与您使用的不同的汇编程序/语法。你通常不需要区域,proc,.function等。汇编程序特定的东西可能会或可能不会帮助你,这取决于你正在做什么(当然使它不那么便携)。 gnu汇编程序(gas)允许.globl或.global声明一些全局的东西,你必须为别人能够让链接器解析那个标签。但是,对于gas externs,不必声明你只需使用一个名称,如果它没有在该汇编步骤(文件+包含)中解析,那么它自动是extern。