Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GCC - how to tell linker not to skip unused sections

Tags:

gcc

linker

cmake

My problem is following:

I am trying to write embedded application, which must have it's own linker script supplied (using arm-none-eabi-gcc compiler/linker).

embedded bootloader loads binary and starts at 0x8000 address, this is why I need a dedicated linker script, which allows me to put desired startup function into this address. Script's code is following:

MEMORY
{
    ram : ORIGIN = 0x8000, LENGTH = 0x1000
}

SECTIONS
{
    .start : { *(.start) } > ram
    .text : { *(.text*) } > ram
    .bss : { *(.bss*) } > ram
}

Having this what I want to do now is to have a function, that will be inserted into .start section, so that it's at the beginning of 0x8000. For this in my library I use following function:

__attribute__((section(".start"))) void notmain() {
    main();
}

This seems to be working fine, but later I link this library with function notmain with the project, which defines main() function. During the link process I can see .start section no more exists and notmain symbol is totally missing. When I move notmain function out of the library (into the project) its'all fine.

My understanding is, that linker sees, that .start section is not used at all in my Application, which makes it skip all the sections. I already tried adding several attributes to function notmain such as (__attribute__((used)) __attribute__((externally_visible))) but it did not work too (notmain is still missing from the final binary).

CMake source code is following:

** Project **

project(AutomaticsControlExample)

enable_language(ASM)

set(CMAKE_CXX_STANDARD 14)

set(SOURCES main.cpp PID.hpp)
set(DEPENDENCIES RPIRuntime PiOS)

add_executable(${PROJECT_NAME} ${SOURCES})
target_link_libraries(${PROJECT_NAME} ${DEPENDENCIES})
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
        COMMAND ${CMAKE_OBJDUMP} -D ${PROJECT_NAME}
        COMMAND ${CMAKE_OBJDUMP} -D ${PROJECT_NAME} > ${PROJECT_NAME}.list
        COMMAND ${CMAKE_OBJCOPY} ${PROJECT_NAME} -O binary ${PROJECT_NAME}.bin
        COMMAND ${CMAKE_OBJCOPY} ${PROJECT_NAME} -O ihex ${PROJECT_NAME}.hex)

** Library **

project(RPIRuntime)

enable_language(ASM)

set(CMAKE_CXX_STANDARD 14)

set(LINKER_SCRIPT memmap)
set(LINKER_FLAGS "-T ${CMAKE_CURRENT_SOURCE_DIR}/${LINKER_SCRIPT}")


set(SOURCES
        notmain.cpp
        assert.cpp)

add_library(${PROJECT_NAME} STATIC ${SOURCES})
target_link_libraries(${PROJECT_NAME} ${LINKER_FLAGS})

My question is: is there any way to prevent linker from omitting linking .start section?

like image 778
DawidPi Avatar asked Oct 20 '25 15:10

DawidPi


1 Answers

As you know, a static library is an ar archive of object files.

Suppose libfoobar.a contains just foo.o and bar.o. A linkage:

g++ -o prog a.o foo.o bar.o     # A

is not the same as the linkage:

g++ -o prog a.o -lfoobar.   # B

The linker unconditionally consumes every object file in the linkage sequence, so in case A, it links a.o, foo.o, bar.o in prog.

The linker does not unconditionally consume every object file that is a member of a static library in the linkage sequence. A static library is a way of offering to the linker a bunch of object files from which to pick the ones it needs.

Suppose that a.o calls function foo, which is defined in foo.o, and that a.o references nothing defined in bar.o.

In that case, the linker unconditionally links a.o into prog, after which prog contains an undefined reference to foo, for which the linker needs a definition. Next it reaches libfoobar.a and inspects the archive (by its index, normally) to see if any member of the archive defines foo. It finds that foo.o does so. So it extracts foo.o from the archive and links it. It needs no definitions for any symbols defined in bar.o, so bar.o is not added to the linkage. The linkage B is exactly the same as:

g++ -o prog a.o foo.o

Suppose on the other hand that a.o calls bar, which is defined in bar.o, and references nothing defined in foo.o. In that case, the linkage B is exactly the same as:

g++ -o prog a.o bar.o

So an object file that you insert into a static library for linkage with your executable will never be linked, by default, unless it provides a definition for at least one symbol that is referenced, but not defined, in an object file that has already been linked.

Your function notmain is not referenced in the only object file, main.o that you are explicitly linking in your program. Therefore, when main.o is linked into your program, the program contains no undefined reference to notmain: the linker requires no definition of notmain - it has never heard of notmain - and will not link any object file from within a static library to obtain a definition of notmain. This has nothing to do with linkage sections.

When linking an ordinary program with static libraries, as a matter of course you do it like:

g++ -o prog main.o x.o ... -ly -lz ....

where one of the *.o files - say main.o - is the object file that defines the main function. You never put main.o in one of the static libraries. That's because, in a ordinary program, main is not called in any of the other object files you are explicitly linking, so if main.o was in one of your libraries, the linkage:

g++ -o prog x.o ... -ly -lz ...

would have no need to find a definition of main at any of -ly -lz ..., and no definition of main would be linked.

The case is just the same with your notmain. If you want it linked you can do one of:-

  1. Add -Wl,--undefined=notmain to your linkage options (replacing notmain with the mangled name of notmain, for C++). This will make the linker assume it has an undefined reference to notmain even though it hasn't seen any.

  2. Add the command EXTERN(notmain) to your linker script (again with mangling for C++). This is equivalent to 1.

  3. Explicitly link an object file that defines notmain. Don't put it in a static library.

3 is effectively what you did when you discovered that:

When I move notmain function out of the library (into the project) its'all fine.

For 3, however, you don't need to compile notmain.cpp in your project and any other project that needs notmain.o. You can build it independently, install it in /usr/local/lib and explicitly add /usr/local/lib/notmain.o to the linkage of your project. That would be following the example of GCC itself, which explicitly links the crt*.o startup files of an ordinary program just by appending their absolute names to the linkage, e.g.

/usr/lib/gcc/x86_64-linux-gnu/6/../../../x86_64-linux-gnu/crti.o
...
/usr/lib/gcc/x86_64-linux-gnu/6/../../../x86_64-linux-gnu/crtn.o
like image 131
Mike Kinghan Avatar answered Oct 23 '25 07:10

Mike Kinghan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!