我正在尝试制作一个嵌入式系统。我有一些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”))似乎无法正常工作
答案 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
实际程序集通常用于引导,不需要编译器游戏,不需要经常返回并维护代码,因为编译器游戏,移植更容易等等。