Это возможно и легче всего сделать с помощью 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
Очень образованный и «драгоценный камень» для хранения в этот дождливый день! –