如何在C代码中明确指定一个部分(如.text,.init,.fini)(主要用于arm)?

时间:2017-05-21 03:38:34

标签: gcc bare-metal

我正在尝试制作一个嵌入式系统。我有一些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”))似乎无法正常工作

1 个答案:

答案 0 :(得分:2)

不明白为什么你认为你需要.tinit部分用于裸机。 pi 0的完整工作示例(使用.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中使用init .bss(在.bss之后放置.data并确保.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

如果你想要它们在不同的地方,那么你的链接器脚本会立即变得更加复杂以及你的引导程序(有很多错误的空间)。

唯一的工作是.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来引导C比它的价值更多的工作,gcc将接受汇编文件,如果它是一个Makefile问题你遇到问题,很少有理由使用内联汇编,当你可以使用真正的汇编和更多的东西可靠和可维护。在实际组装中,这些事情是微不足道的。

.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

实际程序集通常用于引导,不需要编译器游戏,不需要经常返回并维护代码,因为编译器游戏,移植更容易等等。