I'm building an embeeded software for STM32 microcontroller with the toolchain GNU Tools for STM32 and I need the binary output without gaps.
The linker produces a gap between sections .text and .rodata. The problem is the alignment of the section .rodata. The issue appears by using of the GNU Tools for STM32 version 9-2020-q2-update. The previous version I had used (7-2018-q2-update) did not produced that issue.
Excerpt from the linker script (it's the same for both GNU Tools versions):
SECTIONS
{
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4); /* PaulV: change that to ALIGN(8) eliminates the gap */
} >FLASH
/* Constant data into "FLASH" Rom type memory */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >FLASH
}
More details:
The version 7-2018-q2-update produces the output without gap.
The .lst file (note that section .rodata is aligned to bound 4):
K4_G1.elf: file format elf32-littlearm
Sections:
Idx Name Size VMA LMA File off Algn
....
3 .text 0001a20c 08100800 08100800 00010800 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
4 .rodata 00009b54 0811aa0c 0811aa0c 0002aa0c 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
and .map file (no gap between the non-empty sections .fini and .rodata):
.fini 0x000000000811aa04 0x8 c:/st/stm32cubeide_1.4.0/stm32cubeide/plugins/com.st.stm32cube.ide.mcu.externaltools.gnu-tools-for-stm32.7-2018-q2-update.win32_1.5.0.202011040924/tools/bin/../lib/gcc/arm-none-eabi/7.3.1/thumb/v7e-m/fpv5/hard/crtn.o
0x000000000811aa0c . = ALIGN (0x4)
0x000000000811aa0c _etext = .
.vfp11_veneer 0x000000000811aa0c 0x0
.vfp11_veneer 0x000000000811aa0c 0x0 linker stubs
.v4_bx 0x000000000811aa0c 0x0
.v4_bx 0x000000000811aa0c 0x0 linker stubs
.iplt 0x000000000811aa0c 0x0
.iplt 0x000000000811aa0c 0x0 c:/st/stm32cubeide_1.4.0/stm32cubeide/plugins/com.st.stm32cube.ide.mcu.externaltools.gnu-tools-for-stm32.7-2018-q2-update.win32_1.5.0.202011040924/tools/bin/../lib/gcc/arm-none-eabi/7.3.1/thumb/v7e-m/fpv5/hard/crtbegin.o
.rodata 0x000000000811aa0c 0x9b54
0x000000000811aa0c . = ALIGN (0x4)
*(.rodata)
.rodata 0x000000000811aa0c 0x8c Src/app_composer/init.o
The version 9-2020-q2-update produces the output with gap.
The .lst file (note that section .rodata is aligned to bound 8, but why?):
K4_G1.elf: file format elf32-littlearm
Sections:
Idx Name Size VMA LMA File off Algn
...
3 .text 0001923c 08100800 08100800 00010800 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
4 .rodata 000061f0 08119a40 08119a40 00029a40 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
and .map file (there is a gap between the non-empty sections .fini and .rodata):
.fini 0x0000000008119a34 0x8 c:/st/stm32cubeide_1.4.0/stm32cubeide/plugins/com.st.stm32cube.ide.mcu.externaltools.gnu-tools-for-stm32.9-2020-q2-update.win32_1.5.0.202011040924/tools/bin/../lib/gcc/arm-none-eabi/9.3.1/thumb/v7e-m+dp/hard/crtn.o
.vfp11_veneer 0x0000000008119a3c 0x0
.vfp11_veneer 0x0000000008119a3c 0x0 linker stubs
.v4_bx 0x0000000008119a3c 0x0
.v4_bx 0x0000000008119a3c 0x0 linker stubs
.iplt 0x0000000008119a3c 0x0
.iplt 0x0000000008119a3c 0x0 c:/st/stm32cubeide_1.4.0/stm32cubeide/plugins/com.st.stm32cube.ide.mcu.externaltools.gnu-tools-for-stm32.9-2020-q2-update.win32_1.5.0.202011040924/tools/bin/../lib/gcc/arm-none-eabi/9.3.1/thumb/v7e-m+dp/hard/crtbegin.o
.rodata 0x0000000008119a40 0x61f0
0x0000000008119a40 . = ALIGN (0x4)
*(.rodata)
.rodata 0x0000000008119a40 0x96 Src/app_composer/init.o
Edit 03/16/2021
There are no sections *(.rodata) in the input object files having
alignment on the boundary 8 or greater.
Changing the section name .rodata to the name .text eliminates the
gap (The same result if I join the sections .text and .rodata content to a
single .text section):
SECTIONS
{
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
/* ... */
. = ALIGN(4);
} >FLASH
/* Constant data into "FLASH" Rom type memory */
.text : /* <-- the same name as the previous section instead of .rodata */
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >FLASH
}
The source code and build settings are also the same for both variants.
What could be the reason for the problem and how could it be solved? Do I missing something?
P.S. Of cause I can change the alignment at the end of .text section to 8. That would be treating the symptoms, but I want to understand the cause.
Thanks in advance for your help!
Run objdump -h on the input object files. I suspect that you will find that the compiler is putting a minimum alignment of 8 on one of the input .rodata sections. The linker then sets the output alignment to the maximum of the input sections.
Related
code is here at commit #489ee1c
I am writing a unix-like kernel following this tutorial for personal learning. Global variable symbols is incorrect when I debug a unix-like kernel wrote by myself.
I start the kernel using
qemu-system-i386 -d cpu_reset -s -S -D ./run.log -drive format=raw,file=os_image -m 8G
there is also a problem that physical memory is only 3GB in code while I set -m 4G.
and start a gdb stoping at init_global_mm_vars() functions
.gdbinit
set arch i386
symbol-file /root/os/2-kernel/kernel.elf
b init_global_mm_vars
target remote localhost:1234
You can see that the address of symbol Kernel_Vmm_End is 0x58d4 ,but used in asm is 0x68d4. all above global variable symbols is incorrect.
Why all the global variable symbols go wrong ?
I found that if I don't use link.ld script and just use -Ttext=0,when link and all problems seem gone.
ENTRY(kernel_main) /* Kernel entry label */
OUTPUT_FORMAT("elf32-i386")
OUTPUT_ARCH(i386)
SECTIONS {
. = 0x0; /* Kernel code is located at 0x0 */
Kernel_Text_Vmm_Start_p = .; /* Export labels */
.text : /* Align at 4KB and load at 4KB */
{
*(.text) /* All text sections from all files */
}
. = ALIGN(0x1000);
Kernel_Rodata_Vmm_Start_p =.;
.rodata ALIGN (0x1000) : AT(ADDR(.rodata)) /* Align at 4KB and load at 4KB */
{
*(.rodata) /* All read-only data sections from all files */
}
. = ALIGN(0x1000);
Kernel_Data_Vmm_Start_p =.;
.data ALIGN (0x1000) : AT(ADDR(.data)) /* Align at 4KB and load at 4KB */
{
*(.data) /* All data sections from all files */
}
. = ALIGN(0x1000);
Kernel_Bss_Vmm_Start_p =.;
.bss ALIGN (0x1000) : AT(ADDR(.bss)) /* Align at 4KB and load at 4KB */
{
*(COMMON) /* All COMMON sections from all files */
*(.bss) /* All bss sections from all files */
}
. = ALIGN(0x1000);
Kernel_Vmm_End_p = .;
}
Still have no idea why this ld script goes wrong?
Yesterday i created my own u-boot module and want to set text base address at 0xd0020010.
But after compiling, in the .map file generated by linker shows like this
inker script and memory map
0x00000000 . = 0x0
0x00000000 . = ALIGN (0x4)
.text 0xd0020010 0x1f0
0xd0020010 __image_copy_start = .
*(.vectors)
*fill* 0xd0020010 0x10 00
.vectors 0xd0020020 0x60 arch/arm/lib/built-in.o
0xd0020020 _start
0xd0020044 _undefined_instruction
0xd0020048 _software_interrupt
0xd002004c _prefetch_abort
0xd0020050 _data_abort
0xd0020054 _not_used
0xd0020058 _irq
0xd002005c _fiq
You can see above the .vectors section, there are 16 bytes of 0x00 which name is "*fill*".
And my link script is like this
SECTIONS
{
. = 0x00000000;
. = ALIGN(4);
.text :
{
__image_copy_start = .;
*(.vectors)
CPUDIR/start.o (.text*)
*(.text*)
}
.........
I tried to remove ALIGH(4), but it stand still. And 0xd0020010 is a aligned address right? So it should have no matter to do with "ALIGH"
Although the 16 bytes of memory are filled by 0x00, which are nop instructions, but i still wonder why there is a "*fill*" section.
I have a microcontroller project using the GCC tool chain.
gcc version 4.7.4 20130913 (release) [ARM/embedded-4_7-branch revision 202601]
The controller has 512k flash memory. The first 64k are occupied by the bootloader and 448k remain for the project. I defined a linker script with the sizes for FLASH and RAM. I also added the sections. Here is an excerpt:
MEMORY
{
FLASH (rx) : ORIGIN = 0x00010000, LENGTH = 448K
RAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K
}
SECTIONS
{
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
} > FLASH
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
_eflash = .;
} >FLASH
/* used by the startup to initialize data */
_sidata = .;
.data : AT ( _sidata )
{
*(.data) /* .data sections */
*(.data*) /* .data* sections */
_edata = .; /* define a global symbol at data end */
} >RAM
}
The linker works fine placing all section at their places. The problem is that the linker does not check if there is enough space for the .data and .data* sections in the FLASH at the location _sidata. The resulting output exceeds the memory size without any warning.
How can I adapt the linker script so that ld will use the initialization data (.data) in the size calculation?
Edit: Is there any command line option to enforce a sensible data placement?
This linker malfunction can be revealed with an ASSERT:
/* used by the startup to initialize data */
_sidata = .;
.data : AT ( _sidata )
{
_sdata = .;
*(.data) /* .data sections */
*(.data*) /* .data* sections */
_edata = .; /* define a global symbol at data end */
} >RAM
/* verify that the initialization data fits in FLASH */
ASSERT(
(_sidata + (_edata - _sdata)) <= (ORIGIN(FLASH) + LENGTH(FLASH)),
"Initialization Data blow up")
}
This is related to GNU linker.If I have a section which is other than .text , .data or .bss how do I tell linker not to include that section in any of those segments.
Ex:
SECTIONS {
.text {}
.data {}
.bss {}
.sec_var {}
}
Actually in my case sec_var has some global variable I dont want it to be part of data segment but by default linker has this concept of orphan section so it tries to put that section in .data. Due to this the final binary size is grown the same .
I read in the GCC linker :
You can use :NONE to tell the linker to not put the section in any segment at all.
Anybody has used it or has any other method so that , sec_var is not placed under .data section ?
something like this,
MEMORY
{
bob : ORIGIN = 0x8000, LENGTH = 0x1000
ted : ORIGIN = 0xA000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > bob
.rodata : { *(.rodata*) } > bob
.bss : { *(.bss*) } > ted
}
I assume you dont really mean that you want .rodata in .text actually but perhaps you want .text and .rodata to be in the same chunk of memory space together...
I am going through Linux kernel source and found _bss_start C varianle in one of assembly files but could not find where it is actully defined and intialized.
It looks like _bss_start is the starting address of the bss segment but where and how it is intialized with values in kernel source ,I am looking into linux source 2.6.25.
I looked into file asm-generic/section.h where it is defined like below
extern char _bss_start[]
but how _bss_start is defined ,is it DS register is being used to intialized it
__bss_start is defined and initialized by the linker. It references the .bss section of the image, which contains statically allocated variables.
Here is a stripped down example of the linker script defining these symbols:
.bss : {
__bss_start = .; /*< __bss_start references this position in the file */
*(.bss) /*< The actual contents of the section */
*(COMMON) /*< The actual contents of the section */
_ebss = . ; /*< _ebss references this position in the file */
}