GCC Linker, символы секции bss равны нулю - PullRequest
0 голосов
/ 26 апреля 2018

Чтобы попытаться понять основы, я написал [или извлек, я думаю] следующий код c и скрипт компоновщика. Полученный двоичный файл работает, и светодиод мигает без проблем. Однако во время отладки я обнаружил, что символы bss_start и bss_end оба содержат значение 0x20000000. BSS нулевой функции в основном пропускается. При выполнении objdump я вижу

20000000 г 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

1 Ответ

0 голосов
/ 26 апреля 2018

Это потому, что унитарная переменная переходит в COMMON вместо .bss. Если бы вы инициализировали его с 0, то он перешел бы в .bss.

Посмотрите на файл карты компоновщика (если у вас его нет, позвольте компоновщику сгенерировать его с помощью -Map), вы должны увидеть что-то вроде этого

.bss            0x0000000020000000        0x4 load address 0x00000000080000e0
                0x0000000020000000                . = ALIGN (0x4)
                0x0000000020000000                __bss_start__ = .
 *(.bss)
                0x0000000020000000                . = ALIGN (0x4)
                0x0000000020000000                __bss_end__ = .
 COMMON         0x0000000020000000        0x4 ./src/app/main.o
                0x0000000020000000                timer_delayCount

Когда COMMON не указано в сценарии компоновщика, компоновщик помещает его куда-то еще, возможно, выводит его в конце.

Более полный скрипт компоновщика имеет следующий .bss раздел

  .bss :
  {
    . = ALIGN(4);
    __bss_start__ = .;
    *(.bss)
    *(.bss*)
    *(COMMON)
    . = ALIGN(4);
    __bss_end__ = .;
  } >RAM

Тогда секция COMMON будет находиться между __bss_start__ и __bss_end__.

К вашему сведению, *(.bss*) позволяет охватить параметр -fdata-sections, когда каждая переменная получает свой собственный сегмент, так что компоновщик может отбросить те, на которые нет ссылок.

...