I assume you've got the ELF specification, or can find it if you want to. As a "cookbook"... perhaps the Nasm source code, or Fasm source code if you'd prefer to see it in assembly language. There's a macro set in the "asmutils" package from
http://asm.sourceforge.net that creates an ELF executable in Nasm's "-f bin" format, but that may be more "minimalist" than what you're looking for.
I think you're correct that offsets start from zero in the linkable object file, but are fixed to their load address (0x8048000) by the linker. I don't think the loader changes it. I think shared objects (like .dll's) are loaded by sys_mmap, which seems to start at 0x40000000 and work upwards. Since an .so wouldn't know in what order it was loaded, they have to be position independent code. There are some "structures" (I guess you'd call 'em) that help with this. You can read more about it in the Nasm Manual than I understand.
Best,
Frank