1

I'm really struggling with linker scripts, so I decided to start with a minimal test and start tweaking things. But removing lines for the default linker script for sections not even in my object file, can cause the executable to grow drastically!


program: wait_input.S

    .intel_syntax noprefix
#include <sys/syscall.h>

    .text
    .globl  _start
_start:
    # read(0,rsp,1)
    xor edi,edi
    mov rsi,rsp
    mov edx,1
    mov eax,SYS_read
    syscall

    # exit(0)
    xor edi,edi
    mov eax,SYS_exit
    syscall

Ultra small, but enough to see it do something. Now build it and grab the default linker script from the verbose output (which is delineated by lines of ====).

$ gcc -c wait_input.S
$ gcc -o wait_input -nostdlib wait_input.o -Wl,--verbose | awk '!/==/ && p; \
/==/ {p=1-p};' > defaultlinker.x

Taking a look we see there are only three sections in the object file (and only one has any data in it), and the resulting executable is small (its more ELF header than code at this point).

$ objdump -h wait_input.o
wait_input.o:     file format elf64-x86-64

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         0000001a  0000000000000000  0000000000000000  00000040  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000000  0000000000000000  0000000000000000  0000005a  2**0
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000000  0000000000000000  0000000000000000  0000005a  2**0
                  ALLOC

$ wc --bytes wait_input
880 wait_input

The default linker script refers to all kinds of sections I don't have in my object file, so I tried to pare it down but then suddenly the executable file ballooned in size. Playing with it a bit, I eventually figured out that just removing two lines (for sections my object file didn't even have!), caused it:

$ sed -i -e "/build-id/d" defaultlinker.x
$ gcc -nostdlib -o wait_input wait_input.S -Wl,-T defaultlinker.x
$ wc --bytes wait_input
880 wait_input
$ sed -i -e "/interp/d" defaultlinker.x
$ gcc -nostdlib -o wait_input wait_input.S -Wl,-T defaultlinker.x
$ wc --bytes wait_input
2098048 wait_input

WHAT!?

Can someone please explain?

I've used linker scripts for microcontrollers before and they were quite straight forward. I'm really struggling to understand them for ELF files. Nothing seems to match the documentation, and the default linker script seems to be missing all kinds of important info.

RabbitEars
  • 361
  • 1
  • 4
  • 6
  • objdump should give you more clues: try things like objdump -s... I seen this happen before when I had a symbol that was set to a specific address, and the linker script wasn't quite right, so the output started at address 0, and padded out to the address of the symbol, resulting in a multi gig object file. – Chris Desjardins Feb 24 '15 at 08:26

0 Answers0