Question

I'm trying to debug a linker problem that I have, when writing a kernel.

The issue is that I have a variable SCAN_CODE_MAPPING that I'm not able to use -- it appears to be empty or something. I can fix this by changing the way I link my program, but I don't know why.

When I look inside the generated binary file using objdump, the data for the variable is definitely there, so there's just something broken with the reference to it.

Here's a gist with both of the linker scripts and the part of the symbol table that's different between the two files.

What confuses me is that both of the symbol tables have all the same symbols, they're all the same length, and they appear to contain the right data. The only difference that I can see is that they're not in the same order.

So far I've tried

  • inspecting the SCAN_CODE_MAPPING memory location to make sure it has the data I expect and hasn't been zeroed out
  • checking that all the symbols are the same
  • checking that all the symbol contents are the same length
  • looking at .data.rel.ro.local to make sure it has the address of the data

One possible clue is this warning:

warning: uninitialized space declared in non-BSS section `.text': zeroing

which I get in both the broken and the correct case.

What should I try next?

Was it helpful?

Solution 2

You can get a ton more information using "readelf".

In particular, take a look at the program headers:

readelf -l program

Your BSS section is quite different than the standard one, which probably causing the warning. Here's what the default looks like on my system:

  .bss            :
  {
   *(.dynbss)
   *(.bss .bss.* .gnu.linkonce.b.*)
   *(COMMON)
   /* Align here to ensure that the .bss section occupies space up to
      _end.  Align after .bss to ensure correct alignment even if the
      .bss section disappears because there are no input sections.
      FIXME: Why do we need it? When there is no .bss section, we don't
      pad the .data section.  */
   . = ALIGN(. != 0 ? 64 / 8 : 1);
  }

If an input section doesn't match anything in your linker script, the linker still has to place it somewhere. Make sure you're covering all the input sections.

Note that there is a difference between sections and segments. Sections are used by the linker, but the only thing the program loader looks at are the segments. The text segment includes the text section, but it also includes other sections. Sections that go into the same segment must be adjacent. So order does matter.

The rodata section usually goes after the text section. These are both read-only during execution and will show up once in your program headers as a LOAD entry with read & execute permissions. That LOAD entry is the text segment.

The bss section usually goes after the data section. These are both writable during execution and will show up once in your program headers as a LOAD entry with read & write permissions. That LOAD entry is the data segment.

If you change the order, it affects how the linker generates the program headers. The program headers, rather than the section headers, are used when loading your program prior to executing it. Make sure to check the program headers when using a custom linker script.

If you can give more specifics about what your actual symptoms are, then it'll be easier to help.

OTHER TIPS

The problem here turned out to be that I was writing an OS, and only 12k of it was being loaded instead of the whole thing. So the linker script was actually working fine.

The main tools I used to understand binaries were:

  • nm
  • objdump
  • readelf
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top