On 5/26/20 9:36 AM, Cary Coutant wrote:
> Actually, the key distinction between ET_EXEC and ET_DYN is whether or
> not the binary has an entry point. That is, ET_EXEC files are meant to
> be exec'ed, and ET_DYN files are meant to be dlopen'ed. This
> distinction predates even the notion of position independence for
> shared libraries. AT&T's original model for shared libraries used
> absolute linking and you had to link the libraries to non-overlapping
> address ranges. I'd be reluctant to change these definitions after so
> long.
>
> But it's still true that we need to mark position-independent
> executables somehow, and it's clear that most platforms have chosen to
> use ET_DYN for that. Ideally, we'd have come up with a better way --
> perhaps a flag on the PT_LOAD record.
>
> Maybe it's too late, and ET_DYN is a fait accompli. Ideas?
>
> -cary
I think ET_DYN is fine as is. The problem is that we're
reading too much into what ET_EXEC and ET_DYN mean in this
discussion. The significant distinction between ET_EXEC and ET_DYN
is that of position independence. EXEC have their addresses fixed at
link-time, while DYN addresses are established by the runtime linker
at runtime. The names (EXEC, DYN) reflect their most common use, but
are a bit misleading --- they're more low level and general than the
names suggest. I'm definitely against trying to rename them though.
Some things are too old and fundamental to mess with.
An entry point (and for non-static executables the interpreter),
are what distinguish an object that can be the main object in a
process (the a.out "executable") from one that can't. The entry point
isn't the the distinction between ET_EXEC and ET_DYN though. Either
can have an entry, or not. For instance, consider this Solaris PIE,
which is ET_DYN, which by necessity also has an entry:
% file /usr/bin/ls
/usr/bin/ls: ELF 64-bit LSB dynamic lib AMD64 Version 1 [SSE2 SSE], position-independent executable, dynamically linked, not stripped, no debugging information available
% elfdump -e /usr/bin/ls
ELF Header
ei_magic: { 0x7f, E, L, F }
ei_class: ELFCLASS64 ei_data: ELFDATA2LSB
ei_osabi: ELFOSABI_SOLARIS ei_abiversion: EAV_SUNW_CURRENT
e_machine: EM_AMD64 e_version: EV_CURRENT
e_type: ET_DYN
e_flags: 0
e_entry: 0x48d0 e_ehsize: 64 e_shstrndx: 32
e_shoff: 0xf878 e_shentsize: 64 e_shnum: 34
e_phoff: 0x40 e_phentsize: 56 e_phnum: 7
(It's the same on Linux --- I just happen to have Solaris at hand)
There is precedence for ET_EXEC that are not used as "executables".
I know that we've used that for "dumped" shared objects in Solaris
(a feature we have since removed). I think that GNU prelink uses the
same idea for its prelinked shared objects. Those ET_EXEC have no
interpreter, or entry point, and so, are not "executables" in the a.out
sense.
Hence, it's not really necessary to mark PIE specifically.
Any ET_DYN with an entry and an interpreter is PIE.
That said, on Solaris, we do tag our PIE explicitly, by setting
the DF_1_PIE dynamic flag to positively identify a PIE built by
our ld, as distinguished from an ad hoc PIE. The difference between
the 2 cases is the presence of those invisible finishing touches that
go into building an object intended to be the a.out (finalizing more
relocations, etc). This marker is informational, but not essential,
and exec() doesn't look at it in making its decision to load it as
an a.out or not. I think it's probably OK to leave tagging PIE as
a non-essential OSABI matter.
Perhaps this would be a more accurate comment?
#define ET_EXEC 2 /* Position-dependent object */
#define ET_DYN 3 /* Position-independent object */
- Ali