【问题标题】:Indirect function call uses odd address间接函数调用使用奇数地址
【发布时间】:2013-04-02 13:03:19
【问题描述】:

当 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 article 描述了拇指模式和 ARM 模式之间的区别。为什么CPU在同一个模式下,直接调用函数时这个偏移量是不可见的?
  • 应该保留奇数地址还是重置位 0 会导致困难? (直到现在我才看到)

【问题讨论】:

标签: gcc arm cortex-m3


【解决方案1】:

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

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>

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

这是您所问问题的一个主要示例,bl 到 C 函数 notmain 不,不能,使用奇数地址。但是要使用bx,您要求函数main的地址,并且该地址作为0x8000069提供给代码,用于地址0x8000068处的函数,如果您在ARMvsometingT上将bx设置为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丢失了两者之间的delta,所以由硬件控制。

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

【讨论】:

  • 反汇编中偶数地址变成偶数地址的描述非常全面。
猜你喜欢
  • 2011-11-05
  • 2019-09-07
  • 2015-06-09
  • 1970-01-01
  • 2011-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多