The objcopy tool makes it easy to embed arbitrary files into an ELF executable:
objcopy --add-section program.file1=file1.dat \
--add-section program.file2=file2.dat \
program program+files
It seems to me that it should be possible for the program+files to access file1 and file2 programmatically without opening and reading any external files. However, there seems to be no easy way to obtain this information from within the running program.
The files were added as named sections of the ELF executable. However, Linux only loads the segments described by the ELF program header table. The sections are never present in that set since they are not necessary for execution.
So while it is possible to obtain a pointer to the currently running program's ELF header, it is pointless since the sections were not loaded at all.
uintptr_t address = getauxval(AT_PHDR) & -4096;
Elf64_Ehdr *elf = (Elf64_Ehdr *) address;
// dangling pointer, sections aren't loaded by the OS
Elf64_Shdr *sections = ((unsigned char *) elf) + elf->e_shoff;
My intention was to search the sections by name at runtime, find the ones prefixed by program. and compute pointers to them so that my code can use them like ordinary memory blocks.
I can't use predefined symbols for this because I want to support an arbitrary number of embedded files, including no embedded file at all. I need to look up these sections at runtime.
Linux will only load segments marked with PT_LOAD. Can these sections be placed in PT_LOAD segments somehow? objcopy does not seem to have the ability to edit the program header table and add new PT_LOAD segments. How would one go about doing that?
You can find the
programon disk (using/proc/self/exe),mmapit1, decode section headers (see this answer) and then compute pointers to sections of interest and use them as you wish.No: that would require rebuilding parts of the executable which are not possible to rebuild without re-linking the entire program.
Update:
If you don't care all that much about memory usage of your program, you could modify the last
LOADsegment to "cover" the entireprogram+files, and then you can skip the separatemmap-- the files would already be in memory.You just need to increase the
.p_fileszand.p_memszsuch thatphdr.p_offset + phdr.p_filesz == file_size.The price is that you'll cause data that normally isn't loaded into memory (e.g. section header, debug sections (if any)) to occupy memory. But with demand paging, the price could be very small -- nothing should access these "extra" memory regions, and so nothing should cause them to be paged in.
P.S. I know of no standard utility that can update
.p_fileszetc, but it's pretty easy to write such patcher inCor inPython.1 You don't have to
mmapthe entireprogram, just the part of it which contains desired section(s).