When build in Debug mode, it works fine, which can be seen from the ‘readelf-a.out’:
45451: 8004b6a0 0 NOTYPE GLOBAL DEFAULT 2 _octopus_init_begin
45452: 8004b6b8 0 NOTYPE GLOBAL DEFAULT 2 _octopus_init_end
45453: 8004b6a0 8 OBJECT GLOBAL DEFAULT 2 A
45454: 8004b6a8 8 OBJECT GLOBAL DEFAULT 2 B
45455: 8004b6b0 8 OBJECT GLOBAL DEFAULT 2 C
But if try to build in release mode (ReleaseSafe), there are no symbols:
My guess would be because of this issue. You can try disabling LTO in your build script, or you can reference the symbols and force the compiler to include them as I’ve done in some of my bare metal code:
Inspecting the symbol table with objdump shows no sign of vtable in release builds even though it’s there in debug builds. When I read the emitted binary I can see no sign of the value of vtable, even though it should be at the start (Actually, I’m compiling for the RPI Pico, so the first 256 bytes are reserved for stage2 boot, but the vtable should be the first address after that). Interestingly, the _reset_handler is placed where the vtable should be, as if KEEP (*(.vtable)) wasn’t there (I know it’s the reset handler both because of objdump and because I have spent way too much time looking at the emitted binary, so I’m now familiar with it).
Not sure if this is helpful, because I am struggling to find documentation or good examples, but I was also just trying to get a magic number as first bytes on my PinePhone binary. I had the same issues with exported symbols being removed on ReleaseSmall. The only work-around I found so far was to use LONG(symbol); in my .ld file. Let me know if you find a better solution please.