Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't garbage collect keep.{text,data,rodata}.* sections #583

Open
wants to merge 1 commit into
base: trunk
Choose a base branch
from

Conversation

Dragorn421
Copy link
Contributor

@Dragorn421 Dragorn421 commented Jul 15, 2024

This allows manually preventing specific sections (that is, specific symbols, since -ffunction-sections -fdata-sections means one section per symbol) from being garbage collected by the linker ld in the case they are not referenced.


For example:

#include <libdragon.h>

char string[] = "hey";

int main()
{
    return 0;
}

The -fdata-sections flag passed to gcc makes the string symbol be put into its own .rodata.string section. Then on linking since that symbol is unreferenced the section is dropped.

This PR changes the linker script n64.ld such that sections named like keep.{text,data,rodata}.* are always linked in regardless of garbage collection.
This allows using the gcc section attribute to put a symbol in a so-named section that would be kept:

__attribute__((section("keep.rodata.string")))
char string[] = "hey";

The section suffix ("string" here) doesn't matter but I'd recommend using the symbol name like -fdata-sections does for simplicity, consistency and avoiding name collisions (EDIT: section names don't collide. that's the point of the linker after all... should we just not have suffixes at all?).

I also made this possible with text and data. Not that it matters where a symbol ends up, afaik having put this string in keep.text.string and having it ending up in the rom elf's .text section would work just fine. (likewise with putting text in .data/.rodata) Still it seems preferable to put things where they're expected.

I did not add this for .bss because that looks like a footgun, for example picture doing __attribute__((section("keep.bss.mydata"))) int mydata;, and later adding an initializer to mydata but not changing the section from keep.bss to keep.data: then the C source makes it look like the variable has that initial value, but it will be linked in the NOLOAD bss section which is 0-initialized regardless.
Note that (afaik) linking a "bss" uninitialized data symbol into a LOAD section such as .data (__attribute__((section("keep.data.mydata"))) int mydata;) will just work, the linker will store 0s in the data section for those bytes.


Other alternatives:

  • LDFLAGS += --require-defined=string in the Makefile but it would be better/easier to control this from the .c where the symbol is
  • just reference the symbol, but this requires hacks/workarounds for performing noops with the symbols without those noops being optimized out

@Dragorn421
Copy link
Contributor Author

I just realized that there is no need for section names to be unique for __attribute__((section)) or in general, neither inside one file or across TUs.
So this could also just be only keeping sections keep.{text,data,rodata} and putting symbols in those, no need to have a .symbolthing suffix. Would that be better?

@asiekierka
Copy link

asiekierka commented Jul 19, 2024

Modern versions of binutils/GCC (GCC 11+, and matching binutils) have __attribute__((retain)). This should do the trick?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants