[lld] [lld/ELF] Add --override-section-flags flag (PR #109454)

Nico Weber via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 20 11:21:47 PDT 2024


nico wrote:

Here's the promised example of using this:

```
% cat prot-elf.cc
#include <sys/mman.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

extern char my_data[];
__attribute__((section(".mydata"))) char my_data[] = "Initial read-only data";

int main() {
    long pagesize = sysconf(_SC_PAGESIZE);
    void* page_start = (void*)((unsigned long)my_data & ~(pagesize - 1));
    if (mprotect(page_start, pagesize, PROT_READ | PROT_WRITE) == 0)
        strcpy(my_data, "New writable data");
   else
        perror("mprotect failed");
}
```

```
$ out/gn/bin/clang prot-elf.cc  -fuse-ld=lld -Wl,--override-section-flags=.mydata=a
```

```
$ ./a.out
-----------------------------------------------
56387607f000-563876080000 r--p 00000000 fd:01 19553804                   /usr/local/google/home/thakis/src/llvm-project/a.out
563876080000-563876081000 r-xp 00000000 fd:01 19553804                   /usr/local/google/home/thakis/src/llvm-project/a.out
563876081000-563876082000 r--p 00000000 fd:01 19553804                   /usr/local/google/home/thakis/src/llvm-project/a.out
563876082000-563876083000 rw-p 00000000 fd:01 19553804                   /usr/local/google/home/thakis/src/llvm-project/a.out
5638a883b000-5638a885c000 rw-p 00000000 00:00 0                          [heap]
*snip*
-----------------------------------------------
my_data: 0x56387607f800; page start: 0x56387607f000
-----------------------------------------------
56387607f000-563876080000 rw-p 00000000 fd:01 19553804                   /usr/local/google/home/thakis/src/llvm-project/a.out
563876080000-563876081000 r-xp 00000000 fd:01 19553804                   /usr/local/google/home/thakis/src/llvm-project/a.out
563876081000-563876082000 r--p 00000000 fd:01 19553804                   /usr/local/google/home/thakis/src/llvm-project/a.out
563876082000-563876083000 rw-p 00000000 fd:01 19553804                   /usr/local/google/home/thakis/src/llvm-project/a.out
5638a883b000-5638a885c000 rw-p 00000000 00:00 0                          [heap]
*snip*
-----------------------------------------------
```

```
$ readelf --segments a.out
There are 11 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000000040 0x0000000000000040
                 0x0000000000000268 0x0000000000000268  R      0x8
  INTERP         0x00000000000002a8 0x00000000000002a8 0x00000000000002a8
                 0x000000000000001c 0x000000000000001c  R      0x1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x00000000000008c8 0x00000000000008c8  R      0x1000
  LOAD           0x00000000000008d0 0x00000000000018d0 0x00000000000018d0
                 0x00000000000002d0 0x00000000000002d0  R E    0x1000
  LOAD           0x0000000000000ba0 0x0000000000002ba0 0x0000000000002ba0
                 0x00000000000001e0 0x0000000000000460  RW     0x1000
  LOAD           0x0000000000000d80 0x0000000000003d80 0x0000000000003d80
                 0x0000000000000078 0x0000000000000079  RW     0x1000
  DYNAMIC        0x0000000000000bb0 0x0000000000002bb0 0x0000000000002bb0
                 0x00000000000001a0 0x00000000000001a0  RW     0x8
  GNU_RELRO      0x0000000000000ba0 0x0000000000002ba0 0x0000000000002ba0
                 0x00000000000001e0 0x0000000000000460  R      0x1
  GNU_EH_FRAME   0x0000000000000818 0x0000000000000818 0x0000000000000818
                 0x0000000000000024 0x0000000000000024  R      0x4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     0x0
  NOTE           0x00000000000002c4 0x00000000000002c4 0x00000000000002c4
                 0x0000000000000020 0x0000000000000020  R      0x4

 Section to Segment mapping:
  Segment Sections...
   00    
   01     .interp
   02     .interp .note.ABI-tag .dynsym .gnu.version .gnu.version_r .gnu.hash .dynstr .rela.dyn .rela.plt .rodata .mydata .eh_frame_hdr .eh_frame
   03     .text .init .fini .plt
   04     .fini_array .init_array .dynamic .got .relro_padding
   05     .data .tm_clone_table .got.plt .bss
   06     .dynamic
   07     .fini_array .init_array .dynamic .got .relro_padding
   08     .eh_frame_hdr
   09    
   10     .note.ABI-tag
```

(In `--sections` output, `.mydata` looks like so:

```
  [11] .mydata           PROGBITS         0000000000000800  00000800
       0000000000000017  0000000000000000   A       0     0     16
```

)

One effect of this is that .mydata ends up in a phrd with .rela.dyn .rela.plt .rodata etc, and when temporarily mapping the first page of .mydata writeable, parts of those other readonly sections temporarily become writeable too. This can be worked around by adding an object file first on the link line that has `.mydata` with page alignment. We can also add a `--section-alignment=glob=value` flag to make this easier later on.

https://github.com/llvm/llvm-project/pull/109454


More information about the llvm-commits mailing list