Search code examples
linuxshared-librariesrhelbinutils

How to embed data in shared library?


For example, I want to embed dicmap.bin to a shared library libxxx.so. I write a program to verify it.

test_dicmap.cpp
#include <stdio.h>
#include <stdint.h>

extern "C" {
extern const uint8_t _binary_dicmap_bin_start[];
extern const uint8_t _binary_dicmap_bin_end[];
extern const void* _binary_dicmap_bin_size;
}

int main()
{
    size_t size = (size_t)&_binary_dicmap_bin_size;
    printf("start=%p, end=%p\nend-start=%zd, size=%zd\n", 
        _binary_dicmap_bin_start, 
        _binary_dicmap_bin_end,
        _binary_dicmap_bin_end - _binary_dicmap_bin_start,
        size);
    printf("data[0..8]=%02x %02x %02x %02x %02x %02x %02x %02x\n", 
            _binary_dicmap_bin_start[0], _binary_dicmap_bin_start[1], 
            _binary_dicmap_bin_start[2], _binary_dicmap_bin_start[3],
            _binary_dicmap_bin_start[4], _binary_dicmap_bin_start[5], 
            _binary_dicmap_bin_start[6], _binary_dicmap_bin_start[7]);
}

But its _start, _end and _size is invalid.

]$ ls dicmap.bin  -l
-rw-rw-r-- 1 kirbyzhou kirbyzhou 198600798 Feb 26 10:58 dicmap.bin

]# objcopy -B i386 -I binary -O elf64-x86-64 dicmap.bin dicmap.o && g++ -o libxxx.so dicmap.o -shared  &&  g++ -L. -lxxx  test_dicmap.cpp
/opt/rh/devtoolset-8/root/usr/libexec/gcc/x86_64-redhat-linux/8/ld: warning: type and size of dynamic symbol `_binary_dicmap_bin_size' are not defined
/opt/rh/devtoolset-8/root/usr/libexec/gcc/x86_64-redhat-linux/8/ld: warning: type and size of dynamic symbol `_binary_dicmap_bin_start' are not defined
/opt/rh/devtoolset-8/root/usr/libexec/gcc/x86_64-redhat-linux/8/ld: warning: type and size of dynamic symbol `_binary_dicmap_bin_end' are not defined

]# ./a.out
start=0x601034, end=0x601034
end-start=0, size=6295604
data[0..8]=00 00 00 00 00 00 00 00

end-start and size should be sizeof dicmap.bin (198600798).

My objcopy is binutils-2.30-54.el7 of rhel7 with devtoolset-8.

I try to add share flags to the .o file, but a error happens:

objcopy -B i386 -I binary -O elf64-x86-64 dicmap.bin dicmap.o --set-section-flag .data=share
objcopy: BFD version 2.30-54.el7 internal error, aborting at elf.c:8869 in _bfd_elf_set_section_contents

objcopy: Please report this bug.

binutils-2.27-41.base.el7_7.1.x86_64 of rhel7 also have the same problem.

Is there any method to help me?


Solution

  • There 2 methods works for me now.

    Method 1: Use objcopy to convert data to ".o", then link to ".so". Then link the ".so" and main code with "-fPIC".

    objcopy -B i386 -I binary -O elf64-x86-64 dicmap.bin dicmap.o
    g++ -shared -fPIC dicmap.o -o libdicmap1.so
    # -fPIC is very import in the following line, 
    # But it is very unusual when you compile and link main code.
    g++ -fPIC test_dicmap.cpp libdicmap1.so -o test_dicmap1-PIC
    

    Method 2: Use assmbler to wrap the data, and store the size in a different way of objcopy.

    g++ -shared -fPIC dicmap3.s -o libdicmap3.so
    g++ test_dicmap3.cpp libdicmap3.so -o test-dicmap3
    

    Codes:

    test_dicmap.cpp:

    #include <stdio.h>
    #include <stdint.h>
    #include <assert.h>
    extern "C" {
    extern const uint8_t _binary_dicmap_bin_start[];
    extern const uint8_t _binary_dicmap_bin_end[];
    extern const void* _binary_dicmap_bin_size;
    }
    int main()
    {
        size_t data_size = (size_t)&_binary_dicmap_bin_size;
        printf("start=%p, end=%p\nend-start=%zd, size=%zd\n", 
            _binary_dicmap_bin_start, 
            _binary_dicmap_bin_end,
            _binary_dicmap_bin_end - _binary_dicmap_bin_start,
            data_size);
        printf("data[0..8]=%02x %02x %02x %02x %02x %02x %02x %02x\n", 
                _binary_dicmap_bin_start[0], _binary_dicmap_bin_start[1], 
                _binary_dicmap_bin_start[2], _binary_dicmap_bin_start[3],
                _binary_dicmap_bin_start[4], _binary_dicmap_bin_start[5], 
                _binary_dicmap_bin_start[6], _binary_dicmap_bin_start[7]);
        assert(_binary_dicmap_bin_end - _binary_dicmap_bin_start == data_size);
    }
    

    test_dicmap3.cpp:

    #include <stdio.h>
    #include <stdint.h>
    #include <assert.h>
    
    extern "C" {
    extern const uint8_t _binary_dicmap_bin_start[];
    extern const uint8_t _binary_dicmap_bin_end[];
    extern const size_t _binary_dicmap_bin_size;
    }
    
    
    int main()
    {
        size_t data_size = _binary_dicmap_bin_size;
        printf("start=%p, end=%p\nend-start=%zd, size=%zd\n", 
            _binary_dicmap_bin_start, 
            _binary_dicmap_bin_end,
            _binary_dicmap_bin_end - _binary_dicmap_bin_start,
        data_size);
        printf("data[0..8]=%02x %02x %02x %02x %02x %02x %02x %02x\n",
                _binary_dicmap_bin_start[0], _binary_dicmap_bin_start[1], 
                _binary_dicmap_bin_start[2], _binary_dicmap_bin_start[3],
                _binary_dicmap_bin_start[4], _binary_dicmap_bin_start[5], 
                _binary_dicmap_bin_start[6], _binary_dicmap_bin_start[7]);
        // _binary_dicmap_bin_end is invalid
        //assert(_binary_dicmap_bin_end - _binary_dicmap_bin_start == data_size);
    }
    

    dicmap3.s:

        .globl  _binary_dicmap_bin_start
        .globl  _binary_dicmap_bin_end
        .globl  _binary_dicmap_bin_size
        .section  .rodata
        .type   _binary_dicmap_bin_start, @object
        .align  8
    _binary_dicmap_bin_start:
        .incbin "dicmap.bin"
        .align  1
        .size   _binary_dicmap_bin_end, 1
    _binary_dicmap_bin_end:
        .byte   0
        .size   _binary_dicmap_bin_start, _binary_dicmap_bin_end - _binary_dicmap_bin_start
        .type   _binary_dicmap_bin_size, @object
        .size   _binary_dicmap_bin_size, 8
        .align  8
    _binary_dicmap_bin_size:
        .quad   _binary_dicmap_bin_end - _binary_dicmap_bin_start
    

    dicmap.bin:

    helloworld