Editing or Adding to ELF string tables

Is it possible to add - or edit - data (the strings) contained within the string table of an ELF executable?

I know I can access the string table with the following code;

while ((scn = elf_nextscn(m_elf, scn)) != 0) {
char *name = 0;
gelf_getshdr(scn, &shdr);
if (shdr.sh_type == SHT_STRTAB) {
if ( shdr.sh_size != 0 ) {
name = elf_strptr(m_elf, shstrndx, (size_t)shdr.sh_name);
std::cout << name << std::endl;
}
}
}

But can I edit - or add - particular fields to it?

I'm trying to add a field which will allow me to easily identify my executables with a particular attribute. Say Add a field in the string table called 'Version : xxxx'.

Thanks.

add:

static char *revision_string="@(#) Revision: myfile.cpp 1.1.0 2008/10/03";

To your source code then use the what command to identify revisions
(see also: ident man page for a similar idea using "$... text here $")

what compile_file

will produce the string above.

Doing a "man elf" I see that the ELF structure is as follows:

 #define EI_NIDENT 16

           typedef struct {
                   unsigned char  e_ident[EI_NIDENT];
                   uint16_t       e_type;
                   uint16_t       e_machine;
                   uint32_t       e_version;
                   ElfN_Addr      e_entry;
                   ElfN_Off       e_phoff;
                   ElfN_Off       e_shoff;
                   uint32_t       e_flags;
                   uint16_t       e_ehsize;
                   uint16_t       e_phentsize;
                   uint16_t       e_phnum;
                   uint16_t       e_shentsize;
                   uint16_t       e_shnum;
                   uint16_t       e_shstrndx;
           } ElfN_Ehdr;

Remarks:

So you have 32 bits to fool around with until someone else defines a flag.

Perhaps I should clarify.

Assume that I don't have the source code - I can't compile extra info into the executable. I only have the binary.

There are various sections in the ELF headers - and after some research I thought that the best place to append strings would be the string tables. But, I'm not sure if it's possible to edit the binary - tho there is a tool called elfedit, written by a sun dev, which does exactly this (well, he modifies the runtime paths), but I can't find its source code. So - I'm assuming this behaviour is exposed in the API via libelf.

Some references -
http://people.freebsd.org/~jkoshy/download/libelf/article.html
Linker and Libraries Guide

Any ideas, guys?

This may be true for the x86 psABI but is not true for IA64, MIPS and more. For example the IA64 psABI specifies the following values for e_flags (Section 4.1.1.6 Table 4-2):

There's a program on Linux called "objcopy" but I couldn't get it to work. The GNU man page says this program can add sections.

Back to ELF layout: There's a "version" section named ".comment". Presumably, here's where you can put version strings. There's also a "notes" segment, a segment being something that contains sections. In here you can put anything you want.
Presumably, just rewriting the executable with the additional headers (containing segment and/or section references) will work.

I'm really curious about this, so let's continue to work together on this.

Try this:
HT Editor the HT Editor.

I gave it a whirrl. While it gave me a nice tree-view of the elf binary, it was not so simple to add or change section data. It appears you have to do it "by hand" -- ie, create a table, calculate the correct pointer, and change the entry in the table for that pointer. Not particularly time-saving. :frowning:

You can use the GNU linker (ld) to create a new executable that's identical as the old one, but additionally contains the section from a new file. Well, in theory. So far I haven't gotten it to work as hoped. Attached are the files you can use for playing around.

First, you take a C source file that contains only static strings:

static char* __version = "sample 1.0";
static char* __author = "otheus@gmail.com";

Second, you compile it as usual with a C compiler to an object file.

gcc -o version_tmp.o -c version.c

Third, create a ld script file that will be used by ldto create an object file containing the static strings in your source, but in a ".comment" section.

SECTIONS
{
  .comment       0 : { *(.rodata) }
  /DISCARD/        : { *(.text .bss .data .comment .note.GNU-stack) }
}

Fourth, use the linker with this special ld script file ("commentsonly.lds") on your object file (created above with the gcc command). Now, instead of the strings being in the ".rodata" section, they are stored in the ".comment" section. Use the -r option so an object file is created.

ld -r -T commentsonly.lds -o version.o version_tmp.o

Finally, relink the original program with the new object file:

ld -o new_executable original_executable version.o

Now you can confirm the data is stored in this file using readelf or objdump:

objdump -s -j .comment new_executable

Here you should see the data you stored in your .c program.

So what happens. When I tried it, I got a segmentation fault. I suspect you have to do some address juggling to get this to work right. Let me know if you get anywhere?

If you want to add a new section to an object file from an outside object file can you not do

objdump --target=<your triplet> --add-section SECTIONNAME==version.o \ 
   old_exe new_exe

objdump will identify the triplet of BFDNAME for the original for you ahead of time. This approoach will only work if .comment is a valid sectionname for your format. It should be a readonly section.

I cannot try this -- I'm on HPUX for the near future.