【发布时间】:2018-04-26 10:08:16
【问题描述】:
为了尝试理解基础知识,我编写了[或提取我猜想]以下 c 代码和链接器脚本。生成的二进制文件可以正常工作,并且 LED 会毫无问题地闪烁。但是,在调试时,我发现 bss_start 和 bss_end 符号的值都为 0x20000000。 bss归零功能基本被跳过。在做 objdump 时,我可以看到
20000000 g O .bss 00000004 timer_delayCount
所以该部分有 4 个字节长,位于 0x20000000 正确位置。并且至少 bss_start 指向正确的内存地址。但是,bss_end 应该指向 0x20000004 [我认为],而不是 0x20000000。
我现在想知道 bss_end 符号在我认为包含四个字节的 *(.bss) 被放置之后没有增加。
微控制器是stm32f103rb,一个cortex-m3芯片。我正在使用 ARM GNU GCC
我的 main.c 文件:
#define _stackInit 0x20005000U
volatile unsigned int * const RCC_APB2ENR = (unsigned int *)0x40021018;
volatile unsigned int * const GPIOA_CRL = (unsigned int *)0x40010800;
volatile unsigned int * const GPIOA_BSR = (unsigned int *)0x40010810;
volatile unsigned int * const GPIOA_BRR = (unsigned int *)0x40010814;
volatile unsigned int * const STK_CTRL = (unsigned int *)0xE000E010;
volatile unsigned int * const STK_LOAD = (unsigned int *)0xE000E014;
volatile unsigned int * const STK_VAL = (unsigned int *)0xE000E018;
volatile unsigned int timer_delayCount;
int main() {
// enable GIOA clock and set PB5 to output
*RCC_APB2ENR |= (unsigned int)0x00000004;
*GPIOA_CRL = (unsigned int)0x44244444;
// COnfigure Systick Timer for 1 millisecond interrupts
*STK_VAL = 0x00;
*STK_LOAD = 7999U; //tick every 1 ms
*STK_CTRL = 0x07;
while (1){
int c, d;
timer_delayCount = 500u;
while(timer_delayCount != 0u);
*GPIOA_BSR = 0x20;
timer_delayCount = 500u;
while(timer_delayCount != 0u);
*GPIOA_BRR = 0x20;
}
}
// Begin and End addresses for the .bss section. Symbols defined in linker script
extern unsigned int __bss_start__;
extern unsigned int __bss_end__;
void __attribute__ ((section(".after_vectors"))) Reset_Handler (void)
{
// Initialize bss section by iterating and clearing word by word.
// It is assumed that the pointers are word aligned.
unsigned int *p = &__bss_start__;
while (p < &__bss_end__) {
*p++ = 0;
}
main();
}
void SysTick_Handler() {
// Decrement to coutner to zero.
if (timer_delayCount != 0u)
{
--timer_delayCount;
}
}
void __attribute__ ((section(".after_vectors"))) Default_Handler(void)
{
while(1);
}
void __attribute__ ((section(".after_vectors"),weak, alias ("Default_Handler"))) NMI_Handler(void);
void __attribute__ ((section(".after_vectors"),weak, alias ("Default_Handler"))) HardFault_Handler(void);
void __attribute__ ((section(".after_vectors"),weak, alias ("Default_Handler"))) MemManage_Handler(void);
void __attribute__ ((section(".after_vectors"),weak, alias ("Default_Handler"))) BusFault_Handler(void);
void __attribute__ ((section(".after_vectors"),weak, alias ("Default_Handler"))) UsageFault_Handler(void);
void __attribute__ ((section(".after_vectors"),weak, alias ("Default_Handler"))) SVC_Handler(void);
void __attribute__ ((section(".after_vectors"),weak, alias ("Default_Handler"))) DebugMon_Handler(void);
void __attribute__ ((section(".after_vectors"),weak, alias ("Default_Handler"))) PendSV_Handler(void);
typedef void(* const pHandler)(void);
// The vector table.
// The linker script to place at correct location in memory.
__attribute__ ((section(".isr_vector"),used)) pHandler __isr_vectors[] =
{
//core exceptions
(pHandler)_stackInit, // Inital Stack Pointer
Reset_Handler, // reset handler
NMI_Handler, // NMI handler
HardFault_Handler, // hard fault handler
MemManage_Handler, // MPU fault handler
BusFault_Handler, // bus fault handler
UsageFault_Handler, // usage fault handler
0x00, // reserved
0x00, // reserved
0x00, // reserved
0x00, // reserved
SVC_Handler, // SVCall handler
DebugMon_Handler, // debug monitor handler
0x00, // reserved
PendSV_Handler, // PendSV handler
SysTick_Handler, // systick handler
};
我的链接器文件:
ENTRY(Reset_Handler)
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K
}
SECTIONS
{
.text : {
*(.isr_vector)
*(.after_vectors)
*(.text)
} > FLASH
.bss : {
__bss_start__ = .; /* symbol for c code to initialize bss section */
*(.bss)
__bss_end__ = .; /* symbol for c code to initialize bss section */
} > RAM
}
编译器命令:
/opt/gcc-arm-none-eabi-7-2017-q4-major/bin/arm-none-eabi-gcc -c -mcpu=cortex-m3 -mthumb -g blinky-interrupt.c -o blinky-interrupt.o
/opt/gcc-arm-none-eabi-7-2017-q4-major/bin/arm-none-eabi-ld -T blinky-interrupt.ld blinky-interrupt.o -o blinky-interrupt.elf
【问题讨论】:
-
如果
timer_delayCount是第一个和最后一个对象,那么 start 和 end 肯定有相同的地址吗?在这种情况下,“end”是 inclusive0x20000004将是其他东西的起始地址,而不是 bss 的结尾。添加第二个对象来证明这一点。 -
@Clifford:如果节中有一个四字节对象时的起始地址和结束地址相同,那么当节中没有对象时,它们是什么?
-
@EricPostpischil:我不知道;我只是在应用奥卡姆剃刀。我想链接器可以完全删除该部分,但几乎不重要,如果没有引用空间,大小无关紧要。
-
通常 gcc 实现通过(伪代码)
memset(start_bss, 0, end_bss - start_bss)或while(start != end) { *start = 0; start++; }初始化 bss(ARM thumb crt 执行后者,尽管 crt 可能是用汇编程序编写的)。所以是的,在这种情况下,如果 bss_end 以 4 结尾是最有意义的。