gpt4 book ai didi

gcc - 间接函数调用使用奇数地址

转载 作者:行者123 更新时间:2023-12-03 03:36:24 25 4
gpt4 key购买 nike

当 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;"
}

虽然指针指向奇数地址,但执行成功。我预计此时会有异常(exception)。为什么它需要那个奇怪的地址,为什么它不会造成伤害。

编辑

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

最佳答案

我从我的一个示例中拼凑出一些东西来快速演示正在发生的事情。

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 编译代码会自动正确执行此操作。

这是您所要求的一个主要示例,C 函数 blnotmain 不会、不能使用奇数地址。但是要使用bx,您需要提供函数main的地址,并且该地址作为地址0x8000068处的函数的0x8000069提供给代码,如果您在ARMvsometingT上对0x800068执行bx,它将切换到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 领先 2 个字节,所以 4 个字节,所以将 0x8000068 - 0x8000054 = 0x14 除以 2,得到 0x00A。这是 pc 的偏移量,也是指令中编码的内容(指令后半部分的 0A)。除以二是基于拇指指令总是 2 字节(当时是这样)的知识,因此如果将偏移量放在 2 字节指令而不是字节中,它们可以达到两倍的距离。因此 lsbit 丢失了两者之间的增量,因此由硬件控制。

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

关于gcc - 间接函数调用使用奇数地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15764833/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com