如何在 C 代码中显式分配一个部分(如 .text、.init、.fini)(主要用于 arm)?

How to explicitly assign a section in C code (like .text, .init, .fini) (mainly for arm)?

我正在尝试制作一个嵌入式系统。我有一些 C 代码,但是,在主函数运行之前,需要进行一些预初始化。有没有办法告诉 gcc 编译器,某个函数要放在 .init 部分而不是 .text 部分?

这是代码:

#include <stdint.h>

#define REGISTERS_BASE 0x3F000000
#define MAIL_BASE 0xB880  // Base address for the mailbox registers
// This bit is set in the status register if there is no space to write into the mailbox
#define MAIL_FULL 0x80000000
// This bit is set in the status register if there is nothing to read from the mailbox
#define MAIL_EMPTY 0x40000000

struct Message
{
  uint32_t messageSize;
  uint32_t requestCode;
  uint32_t tagID;
  uint32_t bufferSize;
  uint32_t requestSize;
  uint32_t pinNum;
  uint32_t on_off_switch;
  uint32_t end;
};

struct Message m =
{
  .messageSize = sizeof(struct Message),
  .requestCode =0,
  .tagID = 0x00038041,
  .bufferSize = 8,
  .requestSize =0,
  .pinNum = 130,
  .on_off_switch = 1,
  .end = 0,
};

void _start()
{
  __asm__
  (
    "mov sp, #0x8000 \n"
    "b main"
  );
}

/** Main function - we'll never return from here */
int main(void)
{
  uint32_t mailbox = MAIL_BASE + REGISTERS_BASE + 0x18;
  volatile uint32_t status;

  do
  {
    status = *(volatile uint32_t *)(mailbox);
  }
  while((status & 0x80000000));

  *(volatile uint32_t *)(MAIL_BASE + REGISTERS_BASE + 0x20) = ((uint32_t)(&m) & 0xfffffff0) | (uint32_t)(8);

  while(1);
}

编辑:使用 __attribute__(section("init")) 似乎不起作用

不明白为什么您认为裸机需要 .init 部分。 pi 零的完整工作示例(使用 .init)

start.s

.section .init

.globl _start
_start:
    mov sp,#0x8000
    bl centry
    b .

so.c

unsigned int data=5;
unsigned int bss;

unsigned int centry ( void )
{
    return(0);
}

so.ld

MEMORY
{
    ram : ORIGIN = 0x8000, LENGTH = 0x1000
}

SECTIONS
{
    .init : { *(.init*) } > ram
    .text : { *(.text*) } > ram
    .bss : { *(.bss*) } > ram
    .data : { *(.data*) } > ram
}

建造

arm-none-eabi-as start.s -o start.o
arm-none-eabi-gcc -O2 -c so.c -o so.o
arm-none-eabi-ld -T so.ld start.o so.o -o so.elf
arm-none-eabi-objdump -D so.elf

Disassembly of section .init:

00008000 <_start>:
    8000:   e3a0d902    mov sp, #32768  ; 0x8000
    8004:   eb000000    bl  800c <centry>
    8008:   eafffffe    b   8008 <_start+0x8>

Disassembly of section .text:

0000800c <centry>:
    800c:   e3a00000    mov r0, #0
    8010:   e12fff1e    bx  lr

Disassembly of section .bss:

00008014 <bss>:
    8014:   00000000    andeq   r0, r0, r0

Disassembly of section .data:

00008018 <data>:
    8018:   00000005    andeq   r0, r0, r5

请注意,如果你做对了,你不需要在 bootstrap 中初始化 .bss(将 .data 放在 .bss 之后,并确保 .data 中至少有一项)

hexdump -C so.bin
00000000  02 d9 a0 e3 00 00 00 eb  fe ff ff ea 00 00 a0 e3  |................|
00000010  1e ff 2f e1 00 00 00 00  05 00 00 00              |../.........|
0000001c

如果你想把它们放在不同的地方,那么是的,你的链接描述文件会立即变得更加复杂,你的 bootstrap(有很多错误空间)。

.init 在这里为您带来的唯一额外工作 IMO 是您可以重新安排链接器命令行

arm-none-eabi-ld -T so.ld so.o start.o -o so.elf

一起摆脱 .init

Disassembly of section .text:

00008000 <_start>:
    8000:   e3a0d902    mov sp, #32768  ; 0x8000
    8004:   eb000000    bl  800c <centry>
    8008:   eafffffe    b   8008 <_start+0x8>

0000800c <centry>:
    800c:   e3a00000    mov r0, #0
    8010:   e12fff1e    bx  lr

Disassembly of section .bss:

00008014 <bss>:
    8014:   00000000    andeq   r0, r0, r0

Disassembly of section .data:

00008018 <data>:
    8018:   00000005    andeq   r0, r0, r5

没问题,工作正常。只需知道使用 gnu ld(可能还有其他),如果您不在链接描述文件中调出某些内容,那么它会按照(在命令行上)显示的顺序填写内容。

编译器是否使用部分或它们的命名是特定于编译器的,因此您必须深入研究特定于编译器的选项,看看是否有任何更改默认值的选项。使用 C 到 bootstrap C 的工作量大于它的价值,如果它是你遇到问题的 Makefile 问题,gcc 将接受汇编文件,当你可以使用真正的汇编时,很少有理由使用内联汇编并拥有更可靠和可维护的东西。在真正的装配中,这些事情都是微不足道的。

.section .helloworld

.globl _start
_start:
    mov sp,#0x8000
    bl centry
    b .


Disassembly of section .helloworld:

00008000 <_start>:
    8000:   e3a0d902    mov sp, #32768  ; 0x8000
    8004:   ebfffffd    bl  8000 <_start>
    8008:   eafffffe    b   8008 <bss>

Disassembly of section .text:

00008000 <centry>:
    8000:   e3a00000    mov r0, #0
    8004:   e12fff1e    bx  lr

Disassembly of section .bss:

00008008 <bss>:
    8008:   00000000    andeq   r0, r0, r0

Disassembly of section .data:

0000800c <data>:
    800c:   00000005    andeq   r0, r0, r5

真正的汇编一般用于bootstrapping,不需要编译器游戏,不需要因为编译器游戏而经常回头维护代码,移植更容易等