5

I've done a bunch of reading on dynamic linker relocations and position independent code including procedure linkage tables and global offset tables. I don't understand why a statically linked executable needs a PLT and GOT. I compiled a hello world program on my ubuntu x86_64 machine and when I dump the section headers with readelf -S it shows PLT and GOT sections.

I also created a shared library with a simple increment function that I compiled with gcc -shared without -fpic and I also see PLT and GOT sections. I didn't expect this either.

Mike Sweeney
  • 1,896
  • 2
  • 18
  • 20

2 Answers2

5

I don't understand why a statically linked executable needs a PLT and GOT.

It doesn't.

I compiled a hello world program on my ubuntu x86_64 machine and when I dump the section headers with readelf -S it shows PLT and GOT sections.

This is an accident of implementation. The sections come from crt1.o, and there isn't a separate crt1s.o for fully-static linking, so you end up with .plt and .got entries from there.

You can strip these sections, and the binary will still work:

objcopy -R.got -R.plt a.out a.out2

Note: do not strip .rela.plt, as that section is still needed to implement IFUNCs.

Employed Russian
  • 199,314
  • 34
  • 295
  • 362
  • There was also a `.got.plt` I was able to remove and the executable still ran. As you stated if I removed `.rela.plt` the executable segfaulted. – Mike Sweeney Jan 18 '16 at 20:24
0

I found that gcc generates a .got and .got.lpt when generating position independent code and taking the address of a function defined in another source file.

My test files were:

part1.c:

extern void afunc();

int _start()
{
  return 0x55 & (__SIZE_TYPE__) afunc;
}

part2.c:

void afunc() {}

My test was (substitute your own gcc version):

for o in s 4 3 2 1 0
do
  aarch64-linux-gnu-gcc-10 -fPIC part1.c part2.c -o static.elf -static -nostdlib -O$o &&
  aarch64-linux-gnu-objdump -x static.elf | grep 'GLOBAL_OFFSET'
done

I get the following output for all optimization levels:

0000000000410fd8 l     O .got   0000000000000000 _GLOBAL_OFFSET_TABLE_

Replacing -fPIC with -fno-PIC and the segment goes away.

You can tell if your compiler defaults to -fPIC by running this:

aarch64-linux-gnu-gcc-10 -mcmodel=large -x c - < /dev/null 

From which, I get the error, if it does:

cc1: sorry, unimplemented: code model ‘large’ with ‘-fPIC’
Simon Willcocks
  • 308
  • 1
  • 9