How do I completely get rid of .dynsym, .dynstr, and .dynamic sections?

56 views Asked by At

I have a statically linked binary and I'm trying to size it down. I don't understand why it emits dynamic sections and I don't think it really should.

I think -fpic -fPIC should get rid of all relocations, but there's some left. start.s contains call main but that's within the same segment so there shouldn't be a relocation there either.

My Makefile:

hello: start.s hello.c Makefile
        gcc -o hello -nostartfiles -nostdlib -Wl,--no-dynamic-linker -fpic -fPIC -fno-asynchronous-unwind-tables -s start.s hello.c
        strip -R .comment hello

Result of objdump -x

hello:     file format elf64-x86-64
hello
architecture: i386:x86-64, flags 0x00000150:
HAS_SYMS, DYNAMIC, D_PAGED
start address 0x0000000000001000

Program Header:
    LOAD off    0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**12
         filesz 0x0000000000000261 memsz 0x0000000000000261 flags r--
    LOAD off    0x0000000000001000 vaddr 0x0000000000001000 paddr 0x0000000000001000 align 2**12
         filesz 0x00000000000000bb memsz 0x00000000000000bb flags r-x
    LOAD off    0x0000000000002000 vaddr 0x0000000000002000 paddr 0x0000000000002000 align 2**12
         filesz 0x0000000000000010 memsz 0x0000000000000010 flags r--
    LOAD off    0x0000000000002f30 vaddr 0x0000000000003f30 paddr 0x0000000000003f30 align 2**12
         filesz 0x00000000000000d0 memsz 0x00000000000000d0 flags rw-
 DYNAMIC off    0x0000000000002f30 vaddr 0x0000000000003f30 paddr 0x0000000000003f30 align 2**3
         filesz 0x00000000000000d0 memsz 0x00000000000000d0 flags rw-
    NOTE off    0x0000000000000200 vaddr 0x0000000000000200 paddr 0x0000000000000200 align 2**2
         filesz 0x0000000000000024 memsz 0x0000000000000024 flags r--
   STACK off    0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**4
         filesz 0x0000000000000000 memsz 0x0000000000000000 flags rw-
   RELRO off    0x0000000000002f30 vaddr 0x0000000000003f30 paddr 0x0000000000003f30 align 2**0
         filesz 0x00000000000000d0 memsz 0x00000000000000d0 flags r--

Dynamic Section:
  GNU_HASH             0x0000000000000228
  STRTAB               0x0000000000000260
  SYMTAB               0x0000000000000248
  STRSZ                0x0000000000000001
  SYMENT               0x0000000000000018
  DEBUG                0x0000000000000000
  FLAGS_1              0x0000000008000000

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .note.gnu.build-id 00000024  0000000000000200  0000000000000200  00000200  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .gnu.hash     0000001c  0000000000000228  0000000000000228  00000228  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .dynsym       00000018  0000000000000248  0000000000000248  00000248  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .dynstr       00000001  0000000000000260  0000000000000260  00000260  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .text         000000bb  0000000000001000  0000000000001000  00001000  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  5 .rodata       0000000f  0000000000002000  0000000000002000  00002000  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  6 .eh_frame     00000000  0000000000002010  0000000000002010  00002010  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  7 .dynamic      000000d0  0000000000003f30  0000000000003f30  00002f30  2**3
                  CONTENTS, ALLOC, LOAD, DATA
SYMBOL TABLE:
no symbols
1

There are 1 answers

0
Joshua On

After banging at this for hours I got a working answer. This ld script works.

SECTIONS {
#   . = 0x10000;
    . = 0;
    .text : { *(.text*) *(.rodata*) }
    .note.gnu.build-id : { *(.note.gnu.build-id) }
    .data : ALIGN(4096) { *(.data*) }
    .bss : ALIGN(4096) { *(.bss*) }
    /DISCARD/ : { *(.dynsym) *(.dynstr) *(.dynamic) *(.gnu.hash) }
    /DISCARD/ : { *(.comment) }
}

And the build command is

gcc -o hello -Wl,-T,merge.ld -Wl,--no-dynamic-linker -fpic -fno-asynchronous-unwind-tables -pie -nostartfiles -nostdlib -s start.s hello.c

This will explode if there are any initialized pointers in global variables. Why? Because we are relocatable and we don't have any relocations, so there is literally no way to express that.

const char *message = "Hello, World";

is poison.

const char message[] = "Hello, World";

is fine.

If you need initialized global pointers to work; forfeit ASLR instead by changing that . = 0; to . = 0x10000; line and remove -fpic -fpie from the build instructions.