Steve H
Steve H

Reputation: 493

How to control the section to segment mapping in an ELF file?

So I know that we can add a custom section to an ELF file and have functions and structures enforced to be mapped in to custom sections. This can be done by __atribute__ section("sectionname") Here is a readelf output from my current ELF that has a custom section names .my_custom_section that contains a structure named ver_info

Structure:

typedef struct version_info
{
  int     dd ;
  int      mm;
  int    yy;
  int      hr;
  int      min;
  char      *software_type;
  char   *software_version;
  char    *hex_tools_version;
} version_info;

version_info ver_info __attribute__ ((section(".my_custom_section"))) = {7, 10, 2013, 17, 17, "some_type", "some_sw_version", "some_version"} ;

Here is how the elf read looks like:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .hash             HASH            000000d4 0000d4 00003c 04   A  2   0  4
  [ 2] .dynsym           DYNSYM          00000110 000110 0000a0 10   A  3   5  4
  [ 3] .dynstr           STRTAB          000001b0 0001b0 000026 00   A  0   0  1
  [ 4] .rela.dyn         RELA            000001d8 0001d8 000024 0c   A  2   0  4
  [ 5] .plt              PROGBITS        00001000 001000 000000 00  AX  0   0 16
  [ 6] .text             PROGBITS        00001000 001000 00001c 00  AX  0   0  4
  [ 7] .rodata           PROGBITS        00002000 002000 000027 00   A  0   0  1
  [ 8] .dynamic          DYNAMIC         00004000 003000 000078 08  WA  3   0  4
  [ 9] .got              PROGBITS        00004078 003078 000000 00  WA  0   0  4
  [10] .got.plt          PROGBITS        00004078 003078 000010 04  WA  0   0  8
  [11] .my_custom_sectio PROGBITS        00004088 003088 000020 00  WA  0   0  4
  [12] .bss              NOBITS          000040c0 0030a8 000000 00  WA  0   0  1
  [13] .comment          PROGBITS        00000000 0030a8 000028 01  MS  0   0  1
  [14] .shstrtab         STRTAB          00000000 0030d0 000081 00      0   0  1
  [15] .symtab           SYMTAB          00000000 0033fc 000180 10     16  19  4
  [16] .strtab           STRTAB          00000000 00357c 000075 00      0   0  1

Program Headers:

  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000000 0x00000000 0x00000000 0x001fc 0x001fc R   0x1000
  LOAD           0x001000 0x00001000 0x00001000 0x0001c 0x0001c R E 0x1000
  LOAD           0x002000 0x00002000 0x00002000 0x00027 0x00027 R   0x1000
  LOAD           0x003000 0x00004000 0x00004000 0x000a8 0x000c0 RW  0x1000
  DYNAMIC        0x003000 0x00004000 0x00004000 0x00078 0x00078 RW  0x4

 Section to Segment mapping:
  Segment Sections...
   00     .hash .dynsym .dynstr .rela.dyn
   01     .text
   02     .rodata
   03     .dynamic .got.plt .my_custom_section
   04     .dynamic

In this case my custom section is getting clubbed with .dynamic, .got.plt sections and mapped to segment 03. I want to map this section as a independent segment itself.

Can we have a control over mapping a section to a segment? How would you go about it?

EDIT:
1. Why not dlsym for this structure symbol: The reason I am not so keen on adding this structure as a dynamic symbol is that I am writing an API to read the Version Information (which I plan to have contained in a separate segment), which will ultimately determine if I should dlopen this SO file at all. It is a part of security measure to avoid opening an outdated SO.

2.Use of custom linker script: I am now using a custom linker script that adds the following section:

.my_custom_section() :
  {
    KEEP (*version_info.o (.rodata* ))
  }

This does let me to create a section of desired name and place my data into it. But I am still struggling to avoid this section getting clubbed with .rodata or some other sections.

I am sure that by specifying some configuration in linker script would allow me to map this section as an independent segment but that is exactly what I am trying to figure out.

Upvotes: 3

Views: 3525

Answers (2)

Dabo
Dabo

Reputation: 2373

It might be already irrelevant for you, but it is PHDRS command you were looking for. Here is an example (slightly modified) from Using LD, the GNU linker - PHDRS

PHDRS
{
  headers PT_PHDR PHDRS ;
  interp PT_INTERP ;
  text PT_LOAD FILEHDR PHDRS ;
  data PT_LOAD ;
  dynamic PT_DYNAMIC ;
}

SECTIONS
{
  . = SIZEOF_HEADERS;
  .interp : { *(.interp) } :text :interp
  .text : { *(.text) } :text
  .rodata : { *(.rodata) } :text /* explicitly put in :text */
  ...
  . = . + 0x1000; /* move to a new page in memory */
  .data : { *(.data) } :data
  .dynamic : { *(.dynamic) } :data :dynamic
  ...
}

Here you have 5 segments: headers, interp, text, data, dynamic. Look at rodata section explicitly placed into text segment

Upvotes: 0

Pseudonym
Pseudonym

Reputation: 2696

That this is an instruction that you have to give to the linker. Exactly how you do this depends on which linker you're using.

With GNU ld, the "right" way is to use a custom linker script, which you can provide using the -T option. You can see the default linker script by typing ld --verbose. It's a similar story for other linkers: the BSD linker (as used by Mac OSX), uses an order file (specified with -order_file), the Solaris linker uses a map file (specified with -M), and so on. They all do pretty much the same thing.

Note that each platform and each CPU family generally has its own link specification, so a GNU ld linker script that works on x86_64 targets may not work on ARM, even if they are both Linux. It's a similar story for the BSD family. Generally speaking, you should get your platform's linker script and amend it as needed. You should probably only write your own linker script from scratch if this is for a custom platform (e.g. it's firmware, you're writing your own OS, or what have you).

If this is code that needs to be cross-platform, then there are no good solutions. There are some "wrong" ways to do it which could work, such as hacking with objcopy, but I don't recommend them.

Having said that, you should probably ask yourself if this is really what you want. If what you need is data which some custom tool or framework (e.g. a dynamic link loader) can find easily, can't you use dlsym or the equivalent?

EDIT: It's 7 years later, and I just noticed that there is more information. I hope this isn't too late!

GNU ld has two additional commands in its linker scripts that you may not be aware of: PHDRS and SECTIONS. I've never used them, but they do what you want.

Upvotes: 3

Related Questions