Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

objcopy prepends directory pathname to symbol name

Tags:

c++

c

objcopy

I am tying to use objcopy to include a binary form of a text file into an executable. (At runtime I need the file as a string). This works fine until the linker needs to find the references from the symbol names. The problem is that objcopy prepends the symbol names with the pathname to the file. Since I am using GNU Autotools to ship the package this prepended pathname changes and I don't know what external linker symbol to use in the C/C++ program.

nm libtest.a |grep textfile
textfile.o:
00001d21 D _binary__home_git_textfile_end
00001d21 A _binary__home_git_textfile_size
00000000 D _binary__home_git_textfile_start

libtest.a was produced with (extract from Makefile.am):

SUFFIXES = .txt
.txt.$(OBJEXT):
    objcopy --input binary --output elf32-i386 --binary-architecture i386 $< $@

How can I tell objcopy to only us the stem of the filename as linker symbols? Or is there another way around the problem?

like image 609
ritter Avatar asked Mar 24 '13 03:03

ritter


3 Answers

Generic method of including raw data into ELF is supported by .incbin assembler directive.

The trick is to create template .S file that could look like this:

        .global foo_start
foo_start:
        .incbin "foo.raw"

        .global foo_end
foo_end:    

This file is preprocessed via cpp so we don't have to hardcode file name there, eg. we can write:

        .incbin __raw_file_path__

... and then pass it while compiling:

gcc -D__raw_file_path__='"data/foo.png"' foo.S -c -o data/foo.o

Lastly, as we prepare .S file ourself we can add some extra data and/or information. If you include raw "text files" and want these to be available as C strings you can add '0' byte just after raw data:

        .global foo_start
foo_start:
        .incbin "foo.raw"

        .global foo_end
foo_end:    
        .byte 0

        .global foo_size
foo_size:
        .int foo_end - foo_start

If you want full-blown flexibility, you can of course pre-process file manually to alter any part of it, eg.

.global @sym@_start
@sym@_start:
       .incbin "@file@"
       .global @sym@_end
@sym@_end:

... and then compile it:

sed -e "s,@sym@,passwd,g" -e "s,@file@,/etc/passwd," <foo.S.in | gcc -x assembler-with-cpp - -o passwd.o -c
like image 178
lmctl Avatar answered Oct 13 '22 01:10

lmctl


Somewhat ironically you can use objcopy to solve the problem via the --redefine-sym option that allows renaming of symbols...

If I use objcopy to create an object file from a PNG in another directory:

$ objcopy -I binary -O elf64-x86-64 -B i386 --rename-section .data=.rodata,alloc,load,data,contents,readonly ../../resources/test.png test_png.o

The resulting object has the following symbols:

$readelf -s test_png.o -W

Symbol table '.symtab' contains 5 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000000000     0 SECTION LOCAL  DEFAULT    1
     2: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT    1 _binary_______resources_test_png_start
     3: 0000000000003aaa     0 NOTYPE  GLOBAL DEFAULT    1 _binary_______resources_test_png_end
     4: 0000000000003aaa     0 NOTYPE  GLOBAL DEFAULT  ABS _binary_______resources_test_png_size

These can then be renamed:

$objcopy --redefine-sym _binary_______resources_test_png_start=_binary_test_png_start test_png.o
$objcopy --redefine-sym _binary_______resources_test_png_size=_binary_test_png_size test_png.o
$objcopy --redefine-sym _binary_______resources_test_png_end=_binary_test_png_end test_png.o

Resulting in an object with the symbol names that objcopy would have generated if the PNG had been located in the current directory:

$readelf -s test_png.o -W

Symbol table '.symtab' contains 5 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000000000     0 SECTION LOCAL  DEFAULT    1
     2: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT    1 _binary_test_png_start
     3: 0000000000003aaa     0 NOTYPE  GLOBAL DEFAULT    1 _binary_test_png_end
     4: 0000000000003aaa     0 NOTYPE  GLOBAL DEFAULT  ABS _binary_test_png_size
like image 29
user1976 Avatar answered Oct 13 '22 01:10

user1976


Another alternative which I have used is to cd to the source directory and then give objcopy the basename of the source. In bash, this would be:

cd $(dirname $SOURCE)
objcopy ... $(basename $SOURCE) $TARGET

This way the symbols generated are always _binary_file_name_xxx without the path.

like image 36
jfcl Avatar answered Oct 13 '22 02:10

jfcl