What does KEEP mean in a linker script?
Asked Answered
B

3

63

The LD manual does not explain what the KEEP command does. Below is a snippet from a third-party linker script that features KEEP. What does the KEEP command do in ld?

SECTIONS
{  
    .text :
    {
        . = ALIGN(4);
        _text = .;
        PROVIDE(stext = .);
        KEEP(*(.isr_vector))
        KEEP(*(.init))
        *(.text .text.*)        
        *(.rodata .rodata.*)        
        *(.gnu.linkonce.t.*)
        *(.glue_7)
        *(.glue_7t)
        *(.gcc_except_table)
        *(.gnu.linkonce.r.*)
        . = ALIGN(4);
        _etext = .;
        _sidata = _etext;
        PROVIDE(etext = .);   
            _fini = . ;
                *(.fini)

    } >flash
Borax answered 22/3, 2012 at 17:13 Comment(1)
KEEP is documented in this version of the manual.Cerracchio
N
59

Afaik LD keeps the symbols in the section even if symbols are not referenced. (--gc-sections).

Usually used for sections that have some special meaning in the binary startup process, more or less to mark the roots of the dependency tree.


(For Sabuncu below)

Dependency tree:

If you eliminate unused code, you analyze the code and mark all reachable sections (code+global variables + constants).

So you pick a section, mark it as "used" and see what other (unused) section it references, then you mark those section as "used", and check what they reference etc.

The section that are not marked "used" are then redundant, and can be eliminated.

Since a section can reference multiple other sections (e.g. one procedure calling three different other ones), if you would draw the result you get a tree.

Roots:

The above principle however leaves us with a problem: what is the "first" section that is always used? The first node (root) of the tree so to speak? This is what "keep()" does, it tells the linker which sections (if available) are the first ones to look at. As a consequence these are always linked in.

Typically these are sections that are called from the program loader to perform tasks related to dynamic linking (can be optional, and OS/fileformat dependent), and the entry point of the program.

p.s. (2024), looking at Randomblue's script, it is probably for something embedded and demonstrates another reason for a section to be kept. An ISR (interrupt service routine) can be called by the CPU via some jumptable, or directly via address calculation, and might not be referenced by object code. Therefore it is always KEEP()d.

Nickelic answered 22/3, 2012 at 20:42 Comment(7)
+1 What is the dependency tree? Why is it important to mark its roots? Thanks.Newsom
I add a short explanation to the post.Nickelic
THANK you! You say "...tells the linker which sections (if available) are the first ones to look at." Why wouldn't a section be available if it is marked as KEEP? Maybe I am missing some of the fundamentals here, but this topic is really obscure (yet vital) and I am having difficulty finding resources for educating myself.Newsom
You can imagine e.g. one script and two sets of startup code, one for profiling, one not.Nickelic
Some pedantry: the dependency structure is actually a graph, not a tree. Dependencies can go in both directions, there can even be cycles.Cuba
That depends on if you regard following a dependency or marking an unused section as structure determining action. If you never mark an already marked section, the structure you build is a tree.Nickelic
So I can imagine Keep exactly as volatile keyword in C?Peek
P
20

Minimal Linux IA-32 example that illustrates its usage

main.S

.section .text
.global _start
_start:
    /* Dummy access so that after will be referenced and kept. */
    mov after, %eax
    /*mov keep, %eax*/

    /* Exit system call. */
    mov $1, %eax

    /* Take the exit status 4 bytes after before. */
    mov $4, %ebx
    mov before(%ebx), %ebx

    int $0x80

.section .before
    before: .long 0
/* TODO why is the `"a"` required? */
.section .keep, "a"
    keep: .long 1
.section .after
    after: .long 2

link.ld

ENTRY(_start)
SECTIONS
{
    . = 0x400000;
    .text :
    {
        *(.text)
        *(.before)
        KEEP(*(.keep));
        *(.keep)
        *(.after)
    }
}

Compile and run:

as --32 -o main.o main.S
ld --gc-sections -m elf_i386 -o main.out -T link.ld main.o
./main.out
echo $?

Output:

1

If we comment out the KEEP line the output is:

2

If we either:

  • add a dummy mov keep, %eax
  • remove --gc-sections

The output goes back to 1.

Tested on Ubuntu 14.04, Binutils 2.25.

Explanation

There is no reference to the symbol keep, and therefore its containing section .keep.

Therefore if garbage collection is enabled and we don't use KEEP to make an exception, that section will not be put in the executable.

Since we are adding 4 to the address of before, if the keep section is not present, then the exit status will be 2, which is present on the next .after section.

TODO: nothing happens if we remove the "a" from .keep, which makes it allocatable. I don't understand why that is so: that section will be put inside the .text segment, which because of it's magic name will be allocatable.

Perennial answered 8/10, 2015 at 10:44 Comment(3)
Very clear example, thank you ! However I don't see when it can be useful to use this KEEP statementSigismund
@AxelB I don't have a good example right now, but this kind of stuff tends to show up when writing operating systems/baremetal programs. In this case, the KEEP section is presumably something that would be used by something outside of your program, e.g. a bootloader who reads your binary, or a debugger.Perennial
@AxelB if you git grep into the Linux kernel source tree you can see some examples. I'm not 100% what each of one for, but we can make reasonable guesses by googling their section names. E.g. in x86 they have some king of PLG/GOT system at: github.com/cirosantilli/linux/blob/…Perennial
P
2

Force the linker to keep some specific sections

SECTIONS 
{
....
....

*(.rodata .rodata.*)

KEEP(*(SORT(.scattered_array*)));
}
Photoreconnaissance answered 20/2, 2019 at 4:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.