反汇编后的地址问题

时间:2017-04-29 11:42:02

标签: assembly arm cortex-m bare-metal thumb

我是gnu asm的新手,并且被一些代码搞糊涂了。我写了这样的代码:

.code 16

.text

vectors:

    .word STACKINIT
    .word _start + 1
    ..... (defines vectors)

_start:

    mov r0, #0xAB
    .... (other code)
用arm-none-linux-gnueabi-objdump反汇编后,我得到了以下代码:

00008060 <vectors>:

    8060:   20005000    .word   0x20005000
    8064:   000080d1    .word   0x000080d1
    8068:   000080f9    .word   0x000080f9
  ........

000080d0 <_start>:

    80d0:   20ab        movs    r0, #171    ; 0xab
让我困惑的是地址。为什么向量的起始地址是00008060,而不是0x0000,为什么_start的起始地址是000080d0,而不是0x00d0?感谢。

1 个答案:

答案 0 :(得分:0)

您没有提供足够的信息。使用加一而不是一个是坏的,因为当你得到一个正确的地址时,它将被加号修改并且是错误的。无论如何你永远不需要做加号。这是一个非常简单的工作示例,您可以填补您所拥有的与此之间的空白。

so.s

.thumb
.thumb_func
.global _start
_start:
stacktop: .word 0x20001000
.word reset
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang

.thumb_func
reset:
    @bl notmain
    b hang

.thumb_func
hang:   b .

so.ld

MEMORY
{
    rom : ORIGIN = 0x00000000, LENGTH = 0x1000
    ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
    .text : { *(.text*) } > rom
    .rodata : { *(.rodata*) } > rom
    .bss : { *(.bss*) } > ram
}

构建

arm-none-eabi-as so.s -o so.o
arm-none-eabi-ld -o so.elf -T so.ld so.o
arm-none-eabi-objdump -D so.elf > so.list
arm-none-eabi-objcopy so.elf so.bin -O binary
不管怎么说 - 无论什么都行不通......

00000000 <_start>:
   0:   20001000
   4:   00000041
   8:   00000043
   c:   00000043
  10:   00000043
  14:   00000043
  18:   00000043
  1c:   00000043
  20:   00000043
  24:   00000043
  28:   00000043
  2c:   00000043
  30:   00000043
  34:   00000043
  38:   00000043
  3c:   00000043

00000040 <reset>:
  40:   e7ff        b.n 42 <hang>

00000042 <hang>:
  42:   e7fe        b.n 42 <hang>

将_start移动到前面并不是因为它与零对齐,所以首先在ld命令行上是这样做的,因为没有其他对象它只是在命令行上,但是如果链接器脚本不会调出特定的文件名,然后它会落到命令行排序。对于这种工作,你不关心_start你关心向量表的位置。入口点由硅定义,您没有从使用_start作为入口点的操作系统加载这些程序。

.thumb_func是告诉汇编程序下一个标签是函数的最便宜的方法(因此地址是1或1),你可以使用更详细的语法来声明一个过程或函数,检查程序集输出一个C编译函数,看看这个更详细的方法,并选择你喜欢的。

.thumb vs .code 16应该是可以互换的。最终如果使用cortex-m3或m4或(更大的数字,除了cortex-m0或m1之外的其他东西),你会想要指定

.cpu cortex-m3

-mcpu=cortex-m3

在gas和gcc命令行上。

看来您的链接器脚本移动了_start,或者您的二进制文件中有其他东西没有显示给我们,或者您可能有多个文件来创建您向我们展示的内容,不知道您没有提供足够的信息。我们应该能够拿走你提供的东西,并能够重复它......

修改

对于使用cortex-m芯片的一个特定品牌,用户闪存实际上是0x08000000,当您在该模式下启动时,它们将其映射到0x00000000。窗口是我不知道有多大,所以你可以为.text地址空间为0x00000000或0x08000000构建它,这表明更改链接描述文件如何改变输出。

flash.s

.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20001000
.word reset
.word hang @ NMI
.word hang @ HardFault
.word hang @ MemManage
.word hang @ BusFault
.word hang @ UsageFault
.word hang @ 7
.word hang @ 8
.word hang @ 9
.word hang @ 10
.word hang @ SVCall
.word hang @ DebugMonitor
.word hang @ Reserved
.word hang @ PendSV
.word hang @ SysTick
.word hang @ External interrupt 0
.word hang @ External interrupt 1
.word hang @ External interrupt 2

.thumb_func
reset:
    bl notmain
    b hang

.thumb_func
hang:   b .

.thumb_func
.globl dummy
dummy:
    bx lr

notmain.c

extern void dummy ( unsigned int );
void notmain ( void )
{
    unsigned int ra;
    for(ra=0;ra<100;ra++) dummy(ra);
}

flash.ld

MEMORY
{
    rom : ORIGIN = 0x08000000, LENGTH = 0x1000
    ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > rom
    .rodata : { *(.rodata*) } > rom
    .bss : { *(.bss*) } > ram
}

构建

arm-none-eabi-gcc -Wall -O2 -nostdlib -nostartfiles -ffreestanding  -mcpu=cortex-m0 -mthumb -c notmain.c -o notmain.o
arm-none-eabi-ld -o notmain.elf -T flash.ld flash.o notmain.o
arm-none-eabi-objdump -D notmain.elf > notmain.list
arm-none-eabi-objcopy notmain.elf notmain.bin -O binary

加上它包含一些链接的C代码。

因为flash.o在链接器命令行上的notmain.o之前,它首先进入.text(使用这个通用的链接器脚本)。

08000000 <_start>:
 8000000:   20001000    andcs   r1, r0, r0
 8000004:   0800004d    stmdaeq r0, {r0, r2, r3, r6}
 8000008:   08000053    stmdaeq r0, {r0, r1, r4, r6}
 800000c:   08000053    stmdaeq r0, {r0, r1, r4, r6}
 8000010:   08000053    stmdaeq r0, {r0, r1, r4, r6}
 8000014:   08000053    stmdaeq r0, {r0, r1, r4, r6}
 8000018:   08000053    stmdaeq r0, {r0, r1, r4, r6}
 800001c:   08000053    stmdaeq r0, {r0, r1, r4, r6}
 8000020:   08000053    stmdaeq r0, {r0, r1, r4, r6}
 8000024:   08000053    stmdaeq r0, {r0, r1, r4, r6}
 8000028:   08000053    stmdaeq r0, {r0, r1, r4, r6}

请注意.text现在从链接器脚本的0x08000000开始。这很好,因为它将被这个硬件映射到0x00000000,它将读取地址0x00000004处的值0x0800004d并转移到0x0800004c

0800004c <reset>:
 800004c:   f000 f804   bl  8000058 <notmain>
 8000050:   e7ff        b.n 8000052 <hang>

08000052 <hang>:
 8000052:   e7fe        b.n 8000052 <hang>

08000054 <dummy>:
 8000054:   4770        bx  lr
    ...

08000058 <notmain>:
 8000058:   b510        push    {r4, lr}
 800005a:   2400        movs    r4, #0
 800005c:   1c20        adds    r0, r4, #0
 800005e:   3401        adds    r4, #1
 8000060:   f7ff fff8   bl  8000054 <dummy>
 8000064:   2c64        cmp r4, #100    ; 0x64
 8000066:   d1f9        bne.n   800005c <notmain+0x4>
 8000068:   bd10        pop {r4, pc}
 800006a:   46c0        nop         ; (mov r8, r8)

现在如果你删除挂在假人面前的.thumb_func然后用假人移除它我们很幸运它可以解决

8000060:f7ff fff8 bl 8000054

因为使用了分支链接,所以假设它处于相同模式,但挂起前面的那个使得向量表错误

08000000 <_start>:
 8000000:   20001000    andcs   r1, r0, r0
 8000004:   0800004d    stmdaeq r0, {r0, r2, r3, r6}
 8000008:   08000052    stmdaeq r0, {r1, r4, r6}
 800000c:   08000052    stmdaeq r0, {r1, r4, r6}
 8000010:   08000052    stmdaeq r0, {r1, r4, r6}

在gcc命令行上使用-c并将自己与我自己的链接描述文件链接和/或使用-Xlinker gcc选项为链接器提供链接器脚本(并注意gcc命令行上的文件排序)可以控制你必须在这里做的链接器脚本,因为你在我看来是针对一个没有编写arm linux应用程序的cortex-m处理器。编译器和汇编程序可以被一般地处理,但是你想要避免默认的引导程序(gnu世界中的crt0.o)和链接器脚本,除非你有一个直接针对你的特定平台的gnu构建(默认是针对你的平台)。如果您使用C库,则可以在构建C库时执行此操作。使用裸机,你没有一个系统来调用这么多的C库崩溃。