2017-02-14 5 views
6

У меня есть файл сборки NASM, который я собираю и связываю (на Intel-64 Linux).Как добавить содержимое текстового файла в виде раздела в файле ELF?

Существует текстовый файл, и я хочу, чтобы содержимое текстового файла отображалось в результирующем двоичном файле (как строка, в основном). Бинарный файл является исполняемым файлом ELF.

Мой план состоит в создании новой секции данных readonly в файле ELF (что эквивалентно обычному разделу .rodata).

В идеале, был бы добавлен файл для добавления файла в виде нового раздела в файле elf, или вариант компоновщика для добавления файла дословно.

Возможно ли это?

ответ

14

Это возможно и легче всего сделать с помощью OBJCOPY найдено в BINUTILS. Вы фактически берете файл данных как двоичный вход, а затем выводите его в формат объектного файла, который может быть связан с вашей программой.

OBJCOPY даже произведет символ начала и конца, а также размер области данных, чтобы вы могли ссылаться на них в своем коде. Основная идея заключается в том, что вы захотите сказать, что ваш входной файл двоичный (даже если это текст); что вы будете нацелены на объектный файл x86-64; укажите имя входного файла и имя выходного файла.

Предположим, у нас есть входной файл с именем myfile.txt с содержимым:

the 
quick 
brown 
fox 
jumps 
over 
the 
lazy 
dog 

Нечто подобное было бы отправной точкой:

objcopy --input binary \ 
    --output elf64-x86-64 \ 
    --binary-architecture i386:x86-64 \ 
    myfile.txt myfile.o 

Если вы хотите, чтобы генерировать 32-разрядные объекты, которые вы могли бы использование:

objcopy --input binary \ 
    --output elf32-i386 \ 
    --binary-architecture i386 \ 
    myfile.txt myfile.o 

Выходной файл будет представлять собой файл объекта myfile.o. Если бы мы должны были просмотреть заголовки объектного файла с помощью OBJDUMP и команду, как objdump -x myfile.o мы увидим что-то вроде этого:

myfile.o:  file format elf64-x86-64 
myfile.o 
architecture: i386:x86-64, flags 0x00000010: 
HAS_SYMS 
start address 0x0000000000000000 

Sections: 
Idx Name   Size  VMA    LMA    File off Algn 
    0 .data   0000002c 0000000000000000 0000000000000000 00000040 2**0 
        CONTENTS, ALLOC, LOAD, DATA 
SYMBOL TABLE: 
0000000000000000 l d .data 0000000000000000 .data 
0000000000000000 g  .data 0000000000000000 _binary_myfile_txt_start 
000000000000002c g  .data 0000000000000000 _binary_myfile_txt_end 
000000000000002c g  *ABS* 0000000000000000 _binary_myfile_txt_size 

По умолчанию он создает .data раздел с содержимым файла и создает количество символов, которые могут использоваться для ссылки на данные.

_binary_myfile_txt_start 
_binary_myfile_txt_end 
_binary_myfile_txt_size 

Это фактически адрес стартового байта, конечного байта, и размер данных, которые были помещены в объект из файла myfile.txt. OBJCOPY будет содержать символы на имени входного файла. myfile.txt изменен: myfile_txt и используется для создания символов.

Одна проблема заключается в том, что .data раздел создан, который для чтения/записи/данные, как показано здесь:

Idx Name   Size  VMA    LMA    File off Algn 
    0 .data   0000002c 0000000000000000 0000000000000000 00000040 2**0 
        CONTENTS, ALLOC, LOAD, DATA 

Вы специально запрашиваете .rodata раздел, который будет также указан флаг READONLY.Вы можете использовать опцию --rename-section, чтобы изменить .data на .rodata и указать необходимые флаги. Вы можете добавить это в командной строке:

--rename-section .data=.rodata,CONTENTS,ALLOC,LOAD,READONLY,DATA 

Конечно, если вы хотите, чтобы вызвать раздел нечто иное, чем .rodata с теми же флагами, как только для чтения разделе вы можете изменить .rodata в строке выше до имени, хотите использовать для раздела.

Окончательный вариант команды, который должен сгенерировать тип объекта, который вы хотите это:

objcopy --input binary \ 
    --output elf64-x86-64 \ 
    --binary-architecture i386:x86-64 \ 
    --rename-section .data=.rodata,CONTENTS,ALLOC,LOAD,READONLY,DATA \ 
    myfile.txt myfile.o 

Теперь, когда у вас есть объектный файл, как вы можете использовать это в C кода (в качестве примера). Символы, генерируемые немного необычно и есть разумное объяснение на OS Dev Wiki:

Обычная проблема заключается в получении данных мусора при попытке использовать значение, определенное в сценарии компоновки. Обычно это происходит потому, что они разыменовывают символ. Символ, определенный в скрипте компоновщика (например, _ebss =.;), Является только символом, а не переменной. Если вы получаете доступ к символу, используя extern uint32_t _ebss; а затем попытайтесь использовать _ebss, код попытается прочитать 32-битное целое число по адресу, указанному _ebss.

Решение этого вопроса заключается в том, чтобы принять адрес _ebss либо с помощью его как & _ebss, либо путем определения его как несилизованного массива (extern char _ebss [];) и отбрасывания на целое число. (Запись массива предотвращает случайное чтение из _ebss, как массивы должны быть явно разыменовано)

Имея это в виду, мы могли бы создать этот C файл под названием main.c:

#include <stdint.h> 
#include <stdlib.h> 
#include <stdio.h> 

/* These are external references to the symbols created by OBJCOPY */ 
extern char _binary_myfile_txt_start[]; 
extern char _binary_myfile_txt_end[]; 
extern char _binary_myfile_txt_size[]; 

int main() 
{ 
    char *data_start  = _binary_myfile_txt_start; 
    char *data_end  = _binary_myfile_txt_end; 
    size_t data_size = (size_t)_binary_myfile_txt_size; 

    /* Print out the pointers and size */ 
    printf ("data_start %p\n", data_start); 
    printf ("data_end %p\n", data_end); 
    printf ("data_size %zu\n", data_size); 

    /* Print out each byte until we reach the end */ 
    while (data_start < data_end) 
     printf ("%c", *data_start++); 

    return 0; 
} 

Вы можете компилировать и компоновать с :

gcc -O3 main.c myfile.o 

Вывод должен выглядеть примерно так:

data_start 0x4006a2 
data_end 0x4006ce 
data_size 44 
the 
quick 
brown 
fox 
jumps 
over 
the 
lazy 
dog 

NASM пример использования аналогичен по своей природе к кода C. Следующая программа сборки называется nmain.asm пишет та же строка на стандартный вывод с помощью Linux x86-64 System Calls:

bits 64 
global _start 

extern _binary_myfile_txt_start 
extern _binary_myfile_txt_end 
extern _binary_myfile_txt_size 

section .text 

_start: 
    mov eax, 1      ; SYS_Write system call 
    mov edi, eax      ; Standard output FD = 1 
    mov rsi, _binary_myfile_txt_start ; Address to start of string 
    mov rdx, _binary_myfile_txt_size ; Length of string 
    syscall 

    xor edi, edi      ; Return value = 0 
    mov eax, 60      ; SYS_Exit system call 
    syscall 

Это может быть собран и связан с:

nasm -f elf64 -o nmain.o nmain.asm 
gcc -m64 -nostdlib nmain.o myfile.o 

Вывод должен выглядеть следующим образом:

the 
quick 
brown 
fox 
jumps 
over 
the 
lazy 
dog 
+1

Очень образованный и «драгоценный камень» для хранения в этот дождливый день! –

Смежные вопросы