3

当 ARM Cortex-M3 的 GCC 4.7.3 (20121207) 获取函数的地址时,它不会获得函数的确切地址。我可以在该指针中看到一个错位。

// assume at address 0x00001204;
int foo() {
  return 42;
}

void bar() {
  int(*p)() = &foo;  // p = 0x1205;
  p();               // executed successfully
  foo();             // assembly: "bl 0x00001204;"
}

虽然指针指向一个奇数地址,但执行成功。在这一点上,我预计会有一个例外。为什么它需要那个奇怪的地址,为什么它不疼。

编辑

  • SO文章描述了拇指模式和ARM模式之间的区别。尽管 CPU 处于相同模式,但为什么直接调用函数时该偏移量不可见?
  • 应该保留奇数地址还是重置位 0 会导致困难?(直到现在我才看到)
4

1 回答 1

7

我从我的一个例子中拼凑出一些东西来快速演示发生了什么。

vectors.s

/* vectors.s */
.cpu cortex-m3
.thumb

.word   0x20002000  /* stack top address */
.word   _start      /* 1 Reset */
.word   hang        /* 2 NMI */
.word   hello       /* 3 HardFault */
.word   hang        /* 4 MemManage */
.word   hang        /* 5 BusFault */
.word   hang        /* 6 UsageFault */
.word   hang        /* 7 RESERVED */
.word   hang        /* 8 RESERVED */
.word   hang        /* 9 RESERVED*/
.word   hang        /* 10 RESERVED */
.word   hang        /* 11 SVCall */
.word   hang        /* 12 Debug Monitor */
.word   hang        /* 13 RESERVED */
.word   hang        /* 14 PendSV */
.word   hang        /* 15 SysTick */
.word   hang        /* 16 External Interrupt(0) */
.word   hang        /* 17 External Interrupt(1) */
.word   hang        /* 18 External Interrupt(2) */
.word   hang        /* 19 ...   */

.thumb_func
.global _start
_start:
    /*ldr r0,stacktop */
    /*mov sp,r0*/
    bl notmain
    ldr r0,=notmain
    mov lr,pc
    bx r0
    b hang

.thumb_func
hang:   b .

hello: b .

.thumb_func
.globl PUT32
PUT32:
    str r1,[r0]
    bx lr

.end

blinker01.c

extern void PUT32 ( unsigned int, unsigned int );

int notmain ( void )
{
    PUT32(0x12345678,0xAABBCCDD);
    return(0);
}

生成文件:

#ARMGNU = arm-none-eabi
ARMGNU = arm-none-linux-gnueabi

AOPS = --warn --fatal-warnings 
COPS = -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding 


all : blinker01.gcc.thumb.bin 

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

blinker01.gcc.thumb.o : blinker01.c
    $(ARMGNU)-gcc $(COPS) -mthumb -c blinker01.c -o blinker01.gcc.thumb.o

blinker01.gcc.thumb2.o : blinker01.c
    $(ARMGNU)-gcc $(COPS) -mthumb -mcpu=cortex-m3 -march=armv7-m -c blinker01.c -o blinker01.gcc.thumb2.o

blinker01.gcc.thumb.bin : memmap vectors.o blinker01.gcc.thumb.o
    $(ARMGNU)-ld -o blinker01.gcc.thumb.elf -T memmap vectors.o blinker01.gcc.thumb.o
    $(ARMGNU)-objdump -D blinker01.gcc.thumb.elf > blinker01.gcc.thumb.list
    $(ARMGNU)-objcopy blinker01.gcc.thumb.elf blinker01.gcc.thumb.bin -O binary

拆卸:

Disassembly of section .text:

08000000 <_start-0x50>:
 8000000:   20002000    andcs   r2, r0, r0
 8000004:   08000051    stmdaeq r0, {r0, r4, r6}
 8000008:   0800005d    stmdaeq r0, {r0, r2, r3, r4, r6}
 800000c:   0800005e    stmdaeq r0, {r1, r2, r3, r4, r6}
 8000010:   0800005d    stmdaeq r0, {r0, r2, r3, r4, r6}
 8000014:   0800005d    stmdaeq r0, {r0, r2, r3, r4, r6}
 8000018:   0800005d    stmdaeq r0, {r0, r2, r3, r4, r6}
 800001c:   0800005d    stmdaeq r0, {r0, r2, r3, r4, r6}
 8000020:   0800005d    stmdaeq r0, {r0, r2, r3, r4, r6}
 8000024:   0800005d    stmdaeq r0, {r0, r2, r3, r4, r6}
 8000028:   0800005d    stmdaeq r0, {r0, r2, r3, r4, r6}
 800002c:   0800005d    stmdaeq r0, {r0, r2, r3, r4, r6}
 8000030:   0800005d    stmdaeq r0, {r0, r2, r3, r4, r6}
 8000034:   0800005d    stmdaeq r0, {r0, r2, r3, r4, r6}
 8000038:   0800005d    stmdaeq r0, {r0, r2, r3, r4, r6}
 800003c:   0800005d    stmdaeq r0, {r0, r2, r3, r4, r6}
 8000040:   0800005d    stmdaeq r0, {r0, r2, r3, r4, r6}
 8000044:   0800005d    stmdaeq r0, {r0, r2, r3, r4, r6}
 8000048:   0800005d    stmdaeq r0, {r0, r2, r3, r4, r6}
 800004c:   0800005d    stmdaeq r0, {r0, r2, r3, r4, r6}

08000050 <_start>:
 8000050:   f000 f80a   bl  8000068 <notmain>
 8000054:   4803        ldr r0, [pc, #12]   ; (8000064 <PUT32+0x4>)
 8000056:   46fe        mov lr, pc
 8000058:   4700        bx  r0
 800005a:   e7ff        b.n 800005c <hang>

0800005c <hang>:
 800005c:   e7fe        b.n 800005c <hang>

0800005e <hello>:
 800005e:   e7fe        b.n 800005e <hello>

08000060 <PUT32>:
 8000060:   6001        str r1, [r0, #0]
 8000062:   4770        bx  lr
 8000064:   08000069    stmdaeq r0, {r0, r3, r5, r6}

08000068 <notmain>:
 8000068:   b508        push    {r3, lr}
 800006a:   4803        ldr r0, [pc, #12]   ; (8000078 <notmain+0x10>)
 800006c:   4903        ldr r1, [pc, #12]   ; (800007c <notmain+0x14>)
 800006e:   f7ff fff7   bl  8000060 <PUT32>
 8000072:   2000        movs    r0, #0
 8000074:   bd08        pop {r3, pc}
 8000076:   46c0        nop         ; (mov r8, r8)
 8000078:   12345678    eorsne  r5, r4, #120, 12    ; 0x7800000
 800007c:   aabbccdd    bge 6ef33f8 <_start-0x110cc58>

首先注意hangvs hello,这是一个 gnuism,您需要在汇编中将标签声明为 thumb 函数,以便它实际适用于这种事情。 hang正确声明并且向量表正确使用奇数地址,hello未正确声明并且将偶数地址放入其中。C 编译的代码会自动正确执行此操作。

这是您所问的一个主要示例,blC 函数notmain不会,不能,使用奇数地址。但是要使用bx您询问函数的地址,main并且该地址作为 0x8000069 提供给代码以用于地址 0x8000068 处的函数,如果您在bxARMvsometingT 上执行到 0x800068,它将切换到 arm 模式并最终崩溃如果它命中cortex-m 上的拇指模式(希望崩溃而不是绊倒)bx到一个偶数地址应该立即出错。

08000050 <_start>:
 8000050:   f000 f80a   bl  8000068 <notmain>
 8000054:   4803        ldr r0, [pc, #12]   ; (8000064 <PUT32+0x4>)
 8000056:   46fe        mov lr, pc
 8000058:   4700        bx  r0
 800005a:   e7ff        b.n 800005c <hang>
 8000064:   08000069    stmdaeq r0, {r0, r3, r5, r6}

为什么不能bl奇葩?看看上面bl从 0x8000050 到 0x8000068的编码,pc前面是两个所以 4 字节所以取 0x8000068 - 0x8000054 = 0x14 除以 2 得到 0x00A。pc这是指令中编码的内容(指令后半部分中的 0A)的偏移量。除以二是基于拇指指令始终是 2 个字节(当时很好)的知识,因此如果他们将偏移量放在 2 字节指令而不是字节中,它们可以达到两倍的距离。因此lsbit两者之间的增量丢失了,因此由硬件控制。

您的代码所做的是在一个地方您要求提供奇数地址的拇指函数的地址,另一种情况是查看始终为偶数的分支链接的反汇编。

于 2013-04-02T14:28:10.733 回答