0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

關(guān)于RT-Thread的__bss_end - __bss_start的問題解析

冬至子 ? 來源:lchnu ? 作者:lchnu ? 2023-09-15 17:40 ? 次閱讀

Q1. ELF bss == (bss_end - .stack)?
Q1. 編譯完成后,ELF解析的bss數(shù)值3372,并不等于bss_end - bss_start,而是等于bss_end - sstack。

Step 1. 在RT-Thread Studio中創(chuàng)建一個基于4.0.5和STM32L431RCTx的工程。

編譯完成后,得到的輸出結(jié)果是

arm-none-eabi-size --format=berkeley "rtthread.elf"
text data bss dec hex filename
53632 1816 3372 58820 e5c4 rtthread.elf
Used Size(B) Used Size(KB)
Flash: 55448 B 54.15 KB
RAM: 5188 B 5.07 KB
Flash大?。?5448 = text + data,因為data段的初始值存放在Flash中。
RAM大?。?188 = data + bss,因為R/W變量存放在RAM中。
Step 2. 貼上RT-Thread Studio生成的部分map文件

.stack 0x20000718 0x400 load address 0x0800d898
0x20000718 . = ALIGN (0x4)
0x20000718 _sstack = .
0x20000b18 . = (. + _system_stack_size)
fill 0x20000718 0x400
0x20000b18 . = ALIGN (0x4)
0x20000b18 _estack = .
0x20000b18 __bss_start = .
.bss 0x20000b18 0x92c load address 0x0800dc98
0x20000b18 . = ALIGN (0x4)
0x20000b18 _sbss = .
*(.bss)
.bss 0x20000b18 0x1c c:/rt-threadstudio/repo/extract/toolchain_support_packages/arm/gnu_tools_for_arm_embedded_processors/5.4.1/bin/../lib/gcc/arm-none-eabi/5.4.1/armv7e-m/fpu/crtbegin.o
(.bss. )
.bss.rt_tick 0x20000b34 0x4 ./rt-thread/src/clock.o
.bss.idle 0x20000b38 0x80 ./rt-thread/src/idle.o
.bss.rt_thread_stack
......
.bss.uart_obj 0x2000123c 0xdc ./drivers/drv_usart.o
*(COMMON)
COMMON 0x20001318 0x4 ./rt-thread/src/kservice.o
0x20001318 rt_assert_hook
......
COMMON 0x20001440 0x4 ./libraries/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal.o
0x20001440 uwTick
0x20001444 . = ALIGN (0x4)
0x20001444 _ebss = .
*(.bss.init)
0x20001444 __bss_end = .
0x20001444 _end = .
使用__bss_end - __bss_start = 0x20001444 - 0x20000b18 = 0x92C = 2348D
使用__bss_end - _sstack = 0x20001444 - 0x20000718 = 0xD2C = 3372D
關(guān)注RT-Thread Studio給出的信息,只包含了text,data,bss三個信息,其中,data和bss都是存放在RAM中的。

因此,從分析中可知,Studio編譯完成后:

ELF分析工具給出的bss數(shù)據(jù),包括了*.lds文件中的.stack段, .bss段和.COOMMON段。
data數(shù)據(jù)對應(yīng).data段。
.bss + .COMMON + .stack == ELF bss。
Q2. Which kind of variables are placed in .Common?
Q2. .bss和.common部分的關(guān)系?

Step 1. 在main.c中聲明新全局變量global_uint32_a

rt_uint32_t global_uint32_a;
因為僅僅聲明了變量,而沒有使用該變量,因此編譯器優(yōu)化了這個變量,沒有為它實際分配地址,編譯后,ELF bss沒有變化,依然是3372。

Step 2. 在main函數(shù)中添加對變量的使用,防止編譯器優(yōu)化

在main函數(shù)中增加一條使用LOD_D打印global_uint32_a的語句,發(fā)現(xiàn)bss數(shù)據(jù)從3372變化成3376。

打開map文件,查看global_uint32_a。此時,發(fā)現(xiàn)global_uint32_a被放入到了COMMON段中。

COMMON 0x20001440 0x4 ./libraries/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal.o
0x20001440 uwTick
COMMON 0x20001444 0x4 ./applications/main.o
0x20001444 global_uint32_a
0x20001448 . = ALIGN (0x4)
0x20001448 _ebss = .
*(.bss.init)
0x20001448 __bss_end = .
0x20001448 _end = .
Step 3. 修改global_uint32_a的聲明,在聲明前加入static

static rt_uint32_t global_uint32_a;
編譯后,將gloabal_a放入了.bss段中

.bss.global_uint32_a 0x20001318 0x4 ./applications/main.o
不妨查找map中的COMMON段的變量,rt_object_put_hook, rt_object_take_hook等,它們均是全局變量,在某個*.c文件中被聲明,在其他文件中使用extern方式聲明,在多個文件中均有使用。

RT-Thread代碼中的.bss的變量,均使用了static聲明,該變量的作用域僅限于本文件。若外部文件需要使用,則可以以函數(shù)調(diào)用形式,返回該變量的地址即可。使用這種方式,防止了全局變量滿天飛,在模塊間的解耦較好。

Step 4. 在main.c聲明新變量rt_uint8_t類型的新變量global_uint8_b

再次聲明一個rt_uint8_t類型的新變量global_uint8_b,不使用static描述,且打印該變量防止編譯器優(yōu)化該變量。

rt_uint8_t global_uint8_b;
LOG_D("%d, %d",global_uint32_a, global_uint8_b);
編譯后,ELF bss變化成3380,而不是預(yù)期的從3376變化成3377。原因是RAM 4字節(jié)對齊,在lds文件中使用ALIGN(4)的方式進行了約束。

從生成的map文件中可以看到,global_uint8_b被放置在COMMON中,且下方還有ALIGN(4)和fill(填充)的描述。

COMMON 0x20001448 0x1 ./applications/main.o
0x20001448 global_uint8_b
0x2000144c . = ALIGN (0x4)
fill 0x2000144d 0x3
Step 5. 在board.c中聲明同名、同類型的global_uint8_b

在board.c中聲明同名、同類型的global_uint8_b,且在rt_hw_board_init函數(shù)中對global_uint8_b變量賦值為2,防止編譯器優(yōu)化。

rt_uint8_t global_uint8_b;
RT_WEAK void rt_hw_board_init()
{
global_uint8_b = 2;
.......
}

未在board.c中聲明global_uint8_b之前的編譯結(jié)果和map文件節(jié)選如下所示,global_uint8_b在map文件中出現(xiàn)了3次。

/ board.c中聲明變量之前 /
arm-none-eabi-size --format=berkeley "rtthread.elf"
text data bss dec hex filename
53680 1816 3380 58876 e5fc rtthread.elf
/ map文件節(jié)選,省略部分內(nèi)容 /
Allocating common symbols
Common symbol size file
global_uint8_b 0x1 ./applications/main.o
.....
.bss.global_uint32_a
0x20001318 0x4 ./applications/main.o
*(COMMON)
COMMON 0x2000131c 0x4 ./rt-thread/src/kservice.o
0x2000131c rt_assert_hook
.....
COMMON 0x20001448 0x1 ./applications/main.o
0x20001448 global_uint8_b
0x2000144c . = ALIGN (0x4)
fill 0x20001449 0x3
.....
global_uint8_b ./applications/main.o
在board.c中聲明global_uint8_b之后的編譯結(jié)果和map文件節(jié)選如下所示。global_uint8_b在map文件中出現(xiàn)了3次,但是同時main.o和board.o均引用了該變量。

/ board.c中聲明變量之后 /
arm-none-eabi-size --format=berkeley "rtthread.elf"
text data bss dec hex filename
53692 1816 3380 58888 e608 rtthread.elf
/ map文件節(jié)選,省略部分內(nèi)容 /
Allocating common symbols
Common symbol size file
global_uint8_b 0x1 ./drivers/board.o
.....
.bss.global_uint32_a
0x20001318 0x4 ./applications/main.o
*(COMMON)
COMMON 0x2000131c 0x4 ./rt-thread/src/kservice.o
0x2000131c rt_assert_hook
.....
COMMON 0x20001448 0x1 ./drivers/board.o
0x20001448 global_uint8_b
0x2000144c . = ALIGN (0x4)
fill 0x20001449 0x3
.....
global_uint8_b ./applications/main.o
./drivers/board.o

對比在board.c中聲明變量global_uint8_b的前后,發(fā)現(xiàn)ELF bss均沒有變化。從map文件中可以看到,在鏈接過程中,main.o文件中實際用到的是board.o的值。實際整個工程中只有一個global_uint8_b變量,屬于弱符號。

因為board.c中的rt_hw_board_init函數(shù)先于main.c中的main函數(shù)運行,所以將程序下載到開發(fā)板中,會發(fā)現(xiàn)main函數(shù)中打印出來的global_uint8_b的值為2。

Step 6. 將main.c中的global_uint8_b限制為static

保持上述在board.c中的修改,將main.c中的global_uint8_b變量用static描述。

編譯之后ELF bss增加4個字節(jié),變化成3384,整個工程中會有兩個global_uint8_b變量,且位于不同的地址。

main.c中的global_uint8_b位于.bss,是個強符號
board.c中的global_uint8_b位于COMMON,是個弱符號
下方內(nèi)容是將main.c中的global_uint8_b用static修飾之后的map文件節(jié)選。global_uint8_b在map文件中出現(xiàn)了4次,且main.o和board.o的變量位于不同地址。

/ main.c中的變量用static限制 /
arm-none-eabi-size --format=berkeley "rtthread.elf"
text data bss dec hex filename
53692 1816 3384 58892 e60c rtthread.elf
/ map文件節(jié)選,省略部分內(nèi)容 /
Allocating common symbols
Common symbol size file
global_uint8_b 0x1 ./drivers/board.o
.....
.bss.global_uint32_a
0x20001318 0x4 ./applications/main.o
.bss.global_uint8_b
0x2000131c 0x1 ./applications/main.o
*(COMMON)
fill 0x2000131d 0x3
COMMON 0x20001320 0x4 ./rt-thread/src/kservice.o
0x20001320 rt_assert_hook
.....
COMMON 0x2000144c 0x1 ./drivers/board.o
0x2000144c global_uint8_b
0x20001450 . = ALIGN (0x4)
fill 0x2000144d 0x3
.....
global_uint8_b ./drivers/board.o

雖然board.c中的rt_hw_board_init函數(shù)先于main.c中的main函數(shù)運行,且在board.c中g(shù)lobal_uint8_b的值修改成2,但是將程序下載到開發(fā)板中,打印出來的global_uint8_b的值為0。因為兩者實際處于不同地址。

小結(jié)

綜上所述,形成如下小結(jié):

ELF bss包括了:.stack, .bss, .COMMON,它們的地址均位于RAM。
.bss段中的是強符號,.COMMON段中的是弱符號。
RT-Thread的啟動代碼中_bss_start和_bss_end部分的差值,是強符號的.bss部分和弱符號的.COMMON部分之和,啟動代碼對這部分進行清零操作。
多個文件中有同名的變量不可怕,要有強、弱之分。
加了static修飾的全局變量在.bss;未加static修飾的全局變量在.COMMON。
多字節(jié)對齊,方便CPU對數(shù)據(jù)進行快速訪問。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • RAM
    RAM
    +關(guān)注

    關(guān)注

    8

    文章

    1344

    瀏覽量

    114229
  • RT-Thread
    +關(guān)注

    關(guān)注

    31

    文章

    1239

    瀏覽量

    39453
  • Flash存儲
    +關(guān)注

    關(guān)注

    0

    文章

    38

    瀏覽量

    8265
  • STM32L4
    +關(guān)注

    關(guān)注

    1

    文章

    42

    瀏覽量

    9351
收藏 人收藏

    評論

    相關(guān)推薦

    【OK210試用體驗】u-boot篇 -- u-boot內(nèi)存分布

    。 SDRAM_BASE 和 TEXT_BASE 的定義位于 include/configs/smdkv210.h中,可以根據(jù)自己單板的要求來修改地址。 _end和__bss_start為鏈接腳本文件中最后定義的bss
    發(fā)表于 09-07 16:48

    請問__bss_start是直接表示bss起始地址的值嗎?

    __bss_start.globl _bss_end_bss_end:.word __bss_end/* * 清BSS段 */clear_bss
    發(fā)表于 07-19 05:42

    為什么重定位的時候BSS段不拷貝過去?

    拷貝過去,為什么存儲在SDRAM上u-boot代碼總的大小是:__bss_end__ - _start 呢?代碼重定向拷貝代碼不是只拷貝了除BSS段以外代碼段和數(shù)據(jù)段的大小么?ldr r2
    發(fā)表于 07-29 23:19

    RT-ThreadBSS段清零后就初始化C++構(gòu)造有什么作用呢

    大家好,我現(xiàn)在正在學習RT-Thread,但是在學習啟動代碼的時候有一些疑問:1、在BSS段清零后就初始化C++構(gòu)造有什么作用呢?是必須初始化呢還是這個組件可選?2、在初始化C++構(gòu)造后就直接跳到C
    發(fā)表于 03-21 09:26

    小白求助RT-Thread操作系統(tǒng)的執(zhí)行流程是怎樣的

    ;), (void*)STM32_SRAM_END);#else /* init memory system */ rt_system_heap_init((void*)&__bss_end
    發(fā)表于 04-08 10:43

    RT-THREAD標準版移植使用

    前言:無意在微信看到了GD做活動,想到了第一時間體驗一下,搭配RT-THREAD,也很方便使用。主要:本文只使用keil進行測試驗證,gcc和iar需自行修改硬件準備:GD32F427 start
    發(fā)表于 11-21 16:43

    rt thread studio如何把變量定義到backup sram中 ?

    for initial. */  。 = ALIGN(4);  __rt_init_start = 。;  KEEP(*(SORT(.rti_fn*)))  __rt_init_end
    發(fā)表于 02-14 11:25

    RT-Thread編程指南

    RT-Thread編程指南——RT-Thread開發(fā)組(2015-03-31)。RT-Thread做為國內(nèi)有較大影響力的開源實時操作系統(tǒng),本文是RT-Thread實時操作系統(tǒng)的編程指南
    發(fā)表于 11-26 16:06 ?0次下載

    RT-Thread全球技術(shù)大會:Kconfig在RT-Thread中的工作機制

    RT-Thread全球技術(shù)大會:Kconfig在RT-Thread中的工作機制 ? ? ? ? ? ? ? 審核編輯:彭靜
    的頭像 發(fā)表于 05-27 14:49 ?1410次閱讀
    <b class='flag-5'>RT-Thread</b>全球技術(shù)大會:Kconfig在<b class='flag-5'>RT-Thread</b>中的工作機制

    RT-Thread全球技術(shù)大會:RT-Thread測試用例集合案例

    RT-Thread全球技術(shù)大會:RT-Thread測試用例集合案例 ? ? ? ? ? 審核編輯:彭靜
    的頭像 發(fā)表于 05-27 16:34 ?1967次閱讀
    <b class='flag-5'>RT-Thread</b>全球技術(shù)大會:<b class='flag-5'>RT-Thread</b>測試用例集合案例

    RT-Thread學習筆記 RT-Thread的架構(gòu)概述

    RT-Thread 簡介 作為一名 RTOS 的初學者,也許你對 RT-Thread 還比較陌生。然而,隨著你的深入接觸,你會逐漸發(fā)現(xiàn) RT-Thread 的魅力和它相較于其他同類型 RTOS
    的頭像 發(fā)表于 07-09 11:27 ?4327次閱讀
    <b class='flag-5'>RT-Thread</b>學習筆記 <b class='flag-5'>RT-Thread</b>的架構(gòu)概述

    RT-Thread文檔_RT-Thread 簡介

    RT-Thread文檔_RT-Thread 簡介
    發(fā)表于 02-22 18:22 ?5次下載
    <b class='flag-5'>RT-Thread</b>文檔_<b class='flag-5'>RT-Thread</b> 簡介

    RT-Thread文檔_RT-Thread 潘多拉 STM32L475 上手指南

    RT-Thread文檔_RT-Thread 潘多拉 STM32L475 上手指南
    發(fā)表于 02-22 18:23 ?9次下載
    <b class='flag-5'>RT-Thread</b>文檔_<b class='flag-5'>RT-Thread</b> 潘多拉 STM32L475 上手指南

    RT-Thread文檔_RT-Thread SMP 介紹與移植

    RT-Thread文檔_RT-Thread SMP 介紹與移植
    發(fā)表于 02-22 18:31 ?9次下載
    <b class='flag-5'>RT-Thread</b>文檔_<b class='flag-5'>RT-Thread</b> SMP 介紹與移植

    基于RT-Thread Studio學習

    前期準備:從官網(wǎng)下載 RT-Thread Studio,弄個賬號登陸,開啟rt-thread學習之旅。
    的頭像 發(fā)表于 05-15 11:00 ?3521次閱讀
    基于<b class='flag-5'>RT-Thread</b> Studio學習