Fred gilham 2012-05-22 21:29:25
(Note: I also posted this to comp.os.linux.misc, but this seems like a
better group for it.)
I’m trying to create executables with custom program segments.
Specifically, I’m trying to make it possible to have an application
running under CMU Common Lisp that comes in a single file. There are
good and sufficient reasons IMHO for doing this. 🙂
What I do is to process the CMU Lisp memory image into files that have
ELF headers. Then I use a modified linker script to have ld create an
executable from the C-code based loader .o files that also includes
these ELF files and puts them in their own program segments. Then
when the executable is run, the OS automatically restores them into
the right places in memory.
I’ve gotten everything up to linking the executable to work, but I’ve
run across a problem. When the system loads the file, it sets the
break after the end of my last custom segment, instead of after the
end of the .data segment. The load_elf_binary function in
/usr/src/linux-XXXX/fs/binfmt_elf.c does this.
This causes several problems, the most immediate of which is that
normal C code that accesses global variables gets a segmentation
I was able to get this scheme to work happily under FreeBSD. I ran
into a similar problem as described above with FreeBSD, but was able
to work around it by putting my segments earlier in the program header
table than the .data segment, thereby fooling FreeBSD into thinking
its .data segment is the last one even though mine came later in
memory. Unfortunately Linux is too smart for this.
I’d be interested in hearing if anyone out there knows what I’m
talking about and has any comments on what I’m trying to do. I’d
especially appreciate suggestions on how to do it!
Thanks in advance,
Fred Gilham firstname.lastname@example.org
America does not know the difference between s** and money. It treats
s** like money because it treats s** as a medium of exchange, and it
treats money like s** because it expects its money to get pregnant and
reproduce. — Peter Kreeft
John reiser 2012-05-22 21:29:28
Yup, Linux _sucks_ here. execve() is the _only_ way to set the value
returned by brk(0). The only “solution” is to arrange the PT_LOAD so
that the brk() comes out right, which probably means that your entry
point will have to do some copying or re-mapping (and have its own
internal table of what to do). Or, you could just arrange to
intercept all uses of the brk() syscall, but this is grungy work.
Not being able to set brk(0), and not having a random-access binary
structure equivalent of /proc/self/maps, are the two most glaring
deficiecies in the kernel. They really hurt!