Reverse Engineering Stack Exchange is a question and answer site for researchers and developers who explore the principles of a system through analysis of its structure, function, and operation. Join them; it only takes a minute:

They shouldn't have these sections at all. I did try on my own and I confirm that the section .got and .got.plt are still present even when -static is given to the compiler. But, the .dynamic section is not present. My guess is that they are just empty sections when -static is given.
– perrorJun 2 '13 at 15:34

2 Answers
2

There are a plethora of things programmers do not know about how ELF binaries work internally. And, unfortunately, there's almost no solid references apart from two or three which broadly cover the subject. Many tools (linkers, loaders, assemblers, debuggers, ...) remain a mystery for most of you. When it comes to linkers and loaders, the main reference is Linkers and Loaders by John R. Levine (http://linker.iecc.com/). Another reliable source of information is the official ELF binary format documentation. But these are merely introductions to how a certain, or most, technologies work.

Now, here's an answer to your question (why are the GOT and PLT sections still included in static ELF binaries?): PERFORMANCE.

Notice that at the address 401091 you have a call to a function stored in the PLT (the label is more expressive). Amazingly, at this address 4002d0 you'll find a jump to something stored in the GOT (see below).

First, look at the section's name. Second, if you look closely at the code you'll notice that this function identifies the CPU - by dissecting the return values of the cpuid instruction (4187d6 and 4187f7) - (more accurately the micro architecture and other features such as cache size, ...) you're running your ELF binary on, and then decides which implementation suites that configuration best. This way, the strcpy function called in the above C code will always be the fastest possible, whatever architecture you're on (Intel: Nehalem, Sandy Bridge, Ivy Bridge, Haswell, ...; AMD: Phenom, Opteron, ...; ...). Keep in mind that those fast implementations have been hand optimized and fine tuned for each of the possible target architectures.

So that's what the PLT and GOT sections are used for in your static ELF binary file.

Now, if you want to investigate this yourself, you should compile the C code above with GCC version 4.9 (which is the one I used) using the -static and -g3 (debug symbols) flags. Then, disassemble the binary file using objdump and the -D switch in order to have all the ELF sections. You can then go through all the sections and explore the assembly code. You can also run the binary file using gdb and set breakpoints at key locations and run the program step by step.

@yaspr's answer is great, since this question got some bounty of "Looking for an answer drawing from credible and/or official sources.", let me try to provide some references here.

Generally in my understanding, .PLT and .GOT tables are required here because of performance issues.

BinCFI is published on last year's top 2 computer security conference.

Since the purpose of PLT stubs is to dispatch cross
module calls, it would seem that the targets can only
be exported symbols from other modules. However, recent
versions of gcc support a new function type called
gnu indirect function, which allows a function to have
many different implementations, with the most suitable
one selected at runtime based on factors such as the CPU
type. Currently, many glibc low level functions such as
memcpy, strcmp and strlen use this feature. To support
this feature, a library exports a chooser function that selects at runtime which of the many implementations is
going to be used. These implementation functions may
not be exported at all.

Some other references on how to leverage this feature are listed here.

Well, I avoided citing those references because they can be quite confusing. They are centered around the ifunc attribute which was not the subject of this question, rather the existence of GOT and PLT in a statically linked binary (Agner's CPU blog is a valuable source of info). But of course, additional information is always good, if used wisely ! The thing is, everything I've written in my post I discovered way before the references you posted when I was working on patching/instrumenting static ELF binaries for performance evaluation.
– yasprOct 8 '14 at 9:14