gpt4 book ai didi

assembly - 为什么 GCC 在 LDR 之后产生额外的 ADDS 指令以在 ARM thumb 指令集上加载 .rodata 指针?

转载 作者:行者123 更新时间:2023-12-05 04:28:52 30 4
gpt4 key购买 nike

这段代码:

const char padding[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };

const char myTable[] = { 1, 2, 3, 4 };

int keepPadding() {
return (int)(&padding);
}

int foo() {
return (int)(&myTable); // <-- this is the part I'm looking at
}

为 thumb 指令集编译为以下程序集(为清楚起见缩写)。特别注意 adds 作为 foo 的第二条指令:

...
foo:
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 0, uses_anonymous_args = 0
@ link register save eliminated.
ldr r0, .L5
@ sp needed
adds r0, r0, #10
bx lr
.L6:
.align 2
.L5:
.word .LANCHOR0
.size foo, .-foo
.align 1
.global bar
.syntax unified
.code 16
.thumb_func
.type bar, %function

...
myTable:
.ascii "\001\002\003\004"

看起来它正在将指针 (ldr) 加载到 .rodata 的顶部,然后以编程方式偏移到 myTable 的位置(adds).但为什么不直接加载表本身的地址呢?

注意:当我删除 const 时,它似乎没有 ADDS 指令(在 .data 中使用 myTable )

问题的上下文是我正在尝试手动优化一些 C 固件,并注意到这个 adds 指令似乎是多余的,所以我想知道是否有重组的方法我的代码摆脱它。

注意:这都是针对 ARM thumb 指令集编译如下(使用 arm-none-eabi-gcc 版本 11.2.1):

arm-none-eabi-gcc -Os -c -mcpu=cortex-m0 -mthumb temp.c -S

另请注意:此处的示例代码旨在表示较大代码库的片段。如果 myTable 是唯一编译的东西,那么它会落在 .rodata 中的偏移量 0 处,并且 adds 指令会消失,但这不是典型情况一个真实的场景。为了表示生成此程序集的典型真实场景,我在表格前添加了填充。

另见 here it's reproduced on Godbolt

最佳答案

问题最初只包含这个:

const char myTable[] = { 1, 2, 3, 4 };
int foo() {
return (int)(&myTable);
}


arm-none-eabi-gcc -Os -c -mthumb so.c -o so.o
arm-none-eabi-objdump -D so.o

但它没有产生添加:

Disassembly of section .text:

00000000 <foo>:
0: 4800 ldr r0, [pc, #0] ; (4 <foo+0x4>)
2: 4770 bx lr
4: 00000000 andeq r0, r0, r0

Disassembly of section .rodata:

00000000 <myTable>:
0: 04030201 streq r0, [r3], #-513 ; 0xfffffdff

问题已被编辑以显示可重复的示例,因此此答案已被编辑。但我将只留下答案以寻求相同的解决方案。可能有趣的是,到达 anchor 需要一些组件以避免问题被优化。

所以从你的问题和这个:

const char padding[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
const char myTable[] = { 1, 2, 3, 4 };
int foo() {
return (int)(&myTable);
}

很明显为什么 myTable 的偏移量为 10。

但是填充被优化了,所以你最终还是会得到相同的结果。

所以:

const char padding[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
const char myTable[] = { 1, 2, 3, 4 };
int keepPadding() {
return (int)(&padding);
}
int foo() {
return (int)(&myTable);
}

该函数的名称暗示您已经知道所有这些,并且知道如何制作一个最小示例等。

arm-none-eabi-gcc -Os -c -mthumb so.c -S


foo:
@ Function supports interworking.
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 0, uses_anonymous_args = 0
@ link register save eliminated.
ldr r0, .L5
@ sp needed
adds r0, r0, #10
bx lr
.L6:
.align 2
.L5:
.word .LANCHOR0
.size foo, .-foo
.global myTable
.global padding
.section .rodata
.set .LANCHOR0,. + 0
.type padding, %object
.size padding, 10
padding:
.space 10
.type myTable, %object
.size myTable, 4
myTable:
.ascii "\001\002\003\004"
.ident "GCC: (GNU) 11.2.0"

它正在生成一个 anchor ,然后从 anchor 引用而不是直接引用标签。

我怀疑这是为了优化 ldr。让我们试试:

 arm-none-eabi-gcc -Os -c -mthumb -mcpu=cortex-m4 so.c -S

foo:
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 0, uses_anonymous_args = 0
@ link register save eliminated.
ldr r0, .L5
bx lr
.L6:
.align 2
.L5:
.word .LANCHOR0+10
.size foo, .-foo

00000008 <foo>:
8: 4800 ldr r0, [pc, #0] ; (c <foo+0x4>)
a: 4770 bx lr
c: 0000000a .word 0x0000000a

是的,所以修复了它,但是链接它呢

Disassembly of section .rodata:

00000000 <padding>:
...

0000000a <myTable>:
a: 04030201 streq r0, [r3], #-513 ; 0xfffffdff

Disassembly of section .text:

00000010 <keepPadding>:
10: 4800 ldr r0, [pc, #0] ; (14 <keepPadding+0x4>)
12: 4770 bx lr
14: 00000000 andeq r0, r0, r0

00000018 <foo>:
18: 4801 ldr r0, [pc, #4] ; (20 <foo+0x8>)
1a: 300a adds r0, #10
1c: 4770 bx lr
1e: 46c0 nop ; (mov r8, r8)
20: 00000000 andeq r0, r0, r0

不,希望链接器能够替换 pc-relative 负载并将其转换为 mov r0,#0...节省负载,这(可能)是对非 cortex-m 系统的优化(甚至 cortex-m)。

注意:这也行

arm-none-eabi-gcc -Os -c -mthumb -fno-section-anchors so.c -o so.o

00000008 <foo>:
8: 4800 ldr r0, [pc, #0] ; (c <foo+0x4>)
a: 4770 bx lr
c: 00000000 andeq r0, r0, r0
foo:
@ Function supports interworking.
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 0, uses_anonymous_args = 0
@ link register save eliminated.
ldr r0, .L5
@ sp needed
bx lr
.L6:
.align 2
.L5:
.word myTable
.size foo, .-foo
.global myTable
.section .rodata
.type myTable, %object
.size myTable, 4
myTable:
.ascii "\001\002\003\004"
.global padding
.type padding, %object
.size padding, 10

没有使用 anchor ,直接使用myTable的地址。

从我的角度来看,“为什么”是因为使用了 anchor ,前面的填充导致 myTable 与 anchor 有偏移。因此加载加载 anchor 地址,然后将您从 anchor 地址添加到表中。

为什么是主播?为读者或其他人练习。

关于assembly - 为什么 GCC 在 LDR 之后产生额外的 ADDS 指令以在 ARM thumb 指令集上加载 .rodata 指针?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72483177/

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