> When I build a binary with -pie, the linker produces an ELF file with > ET_DYN in header. So it is pretty much explicitly "a shared library", > I guess... Not really. There has been discussion about whether PIE executables should be ET_EXEC or ET_DYN, and it seems to have come down to ET_DYN for the reason that a PIE executable requires the dynamic loader. What distinguishes an executable from a shared library is the presence of an entry point. > Either way, is there any way to tell the linker not to do these things > and instead produce just a shared library with an entry point? In theory, I think you could build a shared object that has an entry point so it could act as an executable, but you'd need to build some startup files that don't currently exist. For a binary to act as an executable, it needs an entry point, but the entry point is not "main" -- it's "_start", defined in crt1.o, which performs a bunch of runtime initialization before actually calling "main". The crt1.o that comes with your compiler probably has non-PIC code in it, so you can't link it into a shared library. If you wanted to do this strongly enough, you could rewrite the C runtime startup code in crt1.o (and probably also crt0.o, crtbegin.o, and others) to be PIC, then link your payload with those startup files instead of the standard ones, and the -shared option. Since I haven't tried this, I'm not quite sure whether the dynamic loader would be happy with the result, but it also could probably be modified if necessary. Bottom line, what you're asking for is theoretically possible, but not currently supported. -cary