mold icon indicating copy to clipboard operation
mold copied to clipboard

Bug/Feature Wish: Strange warning and selecting the entry point (micro controller support, section order): -u vs -e

Open APokorny opened this issue 4 months ago • 14 comments

I have been quite successful with mold in bare metal systems. I am also quite happy to not having to write magic linker scripts. In those systems you want to create a raw binary that starts with a structure that contains addresses to the interrupt service routines and usually an address that gives you the starting point of the stack. In the past it was considered common sense to mark the "reset" service routine as entry point, I think it makes more sense to select the whole initial structure, to ensure that all of the necessary functions would be added.

I.e. on a STM32H7432 I use:

arm-none-eabi-g++ -mthumb -mcpu=cortex-m7 -march=armv7e-m -mfpu=fpv5-d16 -mfloat-abi=hard \
  -ffunction-sections -fdata-sections -fstack-usage -MMD -MP -gdwarf-4  -Os -g3 -nostartfiles --specs=nano.specs\
   --specs=nosys.specs -Wl,--icf=all -Wl,--relocatable-merge-sections -Wl,--no-undefined -lstdc++ -lsupc++ \
   -Wl,-u,vector_table -Wl,-e,vector_table -Wl,--gc-sections -Wl,--nmagic -Wl,--no-omagic -Wl,--Bno-symbolic -Wl,--static\
   -Wl,--stats -Wl,--start-stop -Wl,--image-base=0x24000000 -Wl,--physical-image-base=0x8000000 \
   -Wl,--section-align=TEXT=8 -Wl,--section-align=BSS=8 -Wl,--section-align=RODATA=8 -Wl,--section-align=DATA=8 
   "-Wl,--section-order==0x8000000 isr_vec  TEXT RODATA =0x30000000 .data_sram1 =0x20000000 .data_dtcm =0x20018000 !__start_stack =0x20020000 !__stop_stack =0x24000000 DATA BSS" -fuse-ld=mold ...

I want to point towards the -e vector_table and -u vector_table parameters. This is an array of addresses of functions. It uses [[gnu::section("isr_vec")]] so that I can order it in the section order parameter:

[[gnu::section("isr_vec")]] VectorAddress vector_table[] = {
    (VectorAddress)(&__stop_stack),
    reset_handler,
    nmi_handler,
    hard_fault_handerl,
    ....
};

With the above I do get the desired behavior, but I still get a warning: mold: warning: entry symbol is not defined: vector_table. According to objdump vector_table is found and placed at 0x800000.

Am I mis-using the entry point parameter?

APokorny avatar Sep 10 '25 14:09 APokorny

Thank you for sharing your experience with embedded programming in mold! The lack of feedback is a critical issue when building features for embedded programming, so I'm glad you are using it.

Regarding the warning message about the entry point address, I believe your vector_table is defined as a local symbol. There are several ways to fix this, as follows:

  • Currently, neither -e nor -u has any effect on your program when that warning message is displayed, so you could simply delete these options from the command line, or
  • define vector_table as a global symbol.

vector_table is not a subject of garbage collection because it's defined in a section whose name is a valid C identifier (i.e. isr_vec, not .isr_vec or something.)

rui314 avatar Sep 11 '25 01:09 rui314

Ok will give this a try.

I think there are one or two other features inside --section-order that would be great. But I do feel bad for requesting them, but rather obliged to donate them:

  • the ability to mark user defined sections as uninitialized, to have them placed in memory but not contribute to the final binary size (PS: this one was simpler than I expected)
  • address size checks similar to the memory region feature of linker scripts: --section-order=" =0x2400000 DATA BSS <0x2402000 " - then warn or fail if contents of the section that ordered right before the "<ADDR" token exceed the given address

APokorny avatar Sep 11 '25 11:09 APokorny

As to the second point, would it be sufficient if --section-order="=0x2400000 DATA BSS =0x2402000" issued a warning like “the address is rewound from 0x2403ffff to 0x2402000”?

rui314 avatar Sep 11 '25 12:09 rui314

Oh of course - havent thought about that!

APokorny avatar Sep 11 '25 14:09 APokorny

the --zero-to-bss change works great. With that I discovered a few symbols that are constant and zero for ever. These previously .rodata symbols get moved to the BSS group:


diff --git a/src/passes.cc b/src/passes.cc
index 3c322828..6ca45140 100644
--- a/src/passes.cc
+++ b/src/passes.cc
@@ -2525,7 +2525,7 @@ void sort_output_sections_regular(Context<E> &ctx) {
 
 template <typename E>
 static std::string_view get_section_order_group(Chunk<E> &chunk) {
-  if (chunk.shdr.sh_type == SHT_NOBITS)
+  if (chunk.shdr.sh_type == SHT_NOBITS && (chunk.shdr.sh_flags & SHF_WRITE))
     return "BSS";
   if (chunk.shdr.sh_flags & SHF_EXECINSTR)
     return "TEXT";
diff --git a/test/zero-to-bss.sh b/test/zero-to-bss.sh
index a809e358..a7818930 100755
--- a/test/zero-to-bss.sh
+++ b/test/zero-to-bss.sh
@@ -5,6 +5,7 @@ cat <<EOF | $CC -o $t/a.o -c -xc -
 #include <stdio.h>
 
 __attribute__((section(".zero"))) char zero[256];
+char const stay_in_rodata[256];
 
 int main() {
   printf("Hello world\n");

So the above keeps them in the RODATA group and keeps them inside the binary as zeros. Yeah this is kind of opposite to the initial motivation. For this project it does not matter either way. I was then trying to rename the symbols to "rodata.zero" to give the user more control.

Then I wondered why those "zeros" do not get folded by ICF. Maybe ICF could also merge read-only NOBITS symbols..

APokorny avatar Sep 12 '25 09:09 APokorny

Read-only BSS is an odd concept because reading from such section will always returns 0 at any time, so they don't have to be in memory at all. So maybe --zero-to-bss should work only for writable sections. For the same reason, I believe you don't generally want to merge read-only BSS sections because such sections should not exist in normal circumstances.

rui314 avatar Sep 12 '25 11:09 rui314

Exactly but we magically created that now :). Hence the suggestion above - to keep the original .rodata-NOBITS away from BSS.

APokorny avatar Sep 12 '25 13:09 APokorny

How about the above change?

rui314 avatar Sep 14 '25 01:09 rui314

Sorry for the delay. Yes perfect!

APokorny avatar Sep 17 '25 08:09 APokorny

On the other topic I tried to make this change: https://github.com/APokorny/mold/tree/feat/detect-overlapping-section-intervals

But warnings are triggered twice i.e:

#include <stdint.h>
#include <stdio.h>

__attribute__((section(".dmastuff"))) char ex[1024];
__attribute__((section(".dmastuff"))) int32_t foo;
__attribute__((section(".dmastuff2"))) char ex2[1024];

int main() {
  printf("Hello world\n");
}
gcc -B. -o testi test.o -fuse-ld=mold -Wl,--image-base=0x5000 -Wl,--section-order='=0x1000 .dmastuff =0x1010 =0x4000 .dmastuff2 =0x5000 TEXT RODATA BSS DATA 0x6000 '  
mold: warning: : symbols ordered to 0x1000 exceed 0x1010 up to 0x1404
mold: warning: : symbols ordered to 0x1000 exceed 0x1010 up to 0x1404

I see that it gets re-run, but I dont understand why in this case.

APokorny avatar Sep 18 '25 08:09 APokorny

I believe it's because the function to layout sections actually runs twice. I can add a warning for you. Besides showing the warning twice, did it work as you expected?

rui314 avatar Sep 19 '25 11:09 rui314

How about the above change?

rui314 avatar Sep 20 '25 03:09 rui314

Yeah this works for me. As of now - I am not missing anything in terms of bare metal / embedded systems support. I will convert another project next week and see how that goes, but I dont expect any troubles.

Thanks a lot!

I give a try in documenting that feature.

APokorny avatar Sep 20 '25 19:09 APokorny

--section-order was undocumented because there's no user. I'll add a description of that command line flag to our man page.

rui314 avatar Sep 21 '25 02:09 rui314