Initial commit
commit
ef72003049
|
@ -0,0 +1,9 @@
|
||||||
|
# https://EditorConfig.org/
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_size = 4
|
||||||
|
charset = "utf-8"
|
||||||
|
indent_style = "space"
|
||||||
|
trim_trailing_whitespace = "true"
|
||||||
|
insert_final_newline = "true"
|
|
@ -0,0 +1,24 @@
|
||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
distribute this software, either in source code form or as a compiled
|
||||||
|
binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
means.
|
||||||
|
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
of this software dedicate any and all copyright interest in the
|
||||||
|
software to the public domain. We make this dedication for the benefit
|
||||||
|
of the public at large and to the detriment of our heirs and
|
||||||
|
successors. We intend this dedication to be an overt act of
|
||||||
|
relinquishment in perpetuity of all present and future rights to this
|
||||||
|
software under copyright law.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||||
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
For more information, please refer to <http://unlicense.org/>
|
|
@ -0,0 +1,98 @@
|
||||||
|
# Blob Object
|
||||||
|
A simple utility for embedding an arbitrary binary blob into an ELF or COFF object file.
|
||||||
|
You can then link your program against that object file to be able to access
|
||||||
|
the binary blob as a C array.
|
||||||
|
|
||||||
|
This project will only be updated rarely, if ever.
|
||||||
|
This isn't because the project has been abandoned;
|
||||||
|
it's just trivial enough that (other than the caveats described below)
|
||||||
|
there are few reasons that an update would be necessary.
|
||||||
|
|
||||||
|
This project is public domain (see `LICENSE`), so feel free to use it however you'd like.
|
||||||
|
Credit is optional.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
This project has no dependencies and can be built with Meson:
|
||||||
|
`meson setup build && cd build && meson compile && sudo meson install`
|
||||||
|
|
||||||
|
You can also compile it manually with your C compiler; meson is just for convenience:
|
||||||
|
```bash
|
||||||
|
cc -o blob-object-elf subprojects/blob-object-elf/src/main.c
|
||||||
|
cc -o blob-object-coff subprojects/blob-object-coff/src/main.c
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
`blob-object-(elf|coff) <output file> <section name> <symbol name> <blob file>`
|
||||||
|
|
||||||
|
You can include the generated blob object in C using these declarations:
|
||||||
|
```c
|
||||||
|
// the size in bytes of the blob. can be uint64_t with ELF, but COFF is restricted to 32-bit.
|
||||||
|
extern uint32_t const <symbol name>_size;
|
||||||
|
// the address of this constant is the beginning of the blob
|
||||||
|
extern uint8_t const <symbol name>;
|
||||||
|
|
||||||
|
// get a reference to your data
|
||||||
|
uint8_t* my_data = &<symbol name>;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example for compiling GLSL shaders to SPIR-V and into your Vulkan program
|
||||||
|
Here's an example of how you might use this to include compiled SPIR-V shaders in your executable:
|
||||||
|
* `glslangValidator -V100 -o "frag_shader.spv" "frag.glsl"`
|
||||||
|
* `blob-object-elf frag_shader.o shaders frag_shader frag_shader.spv`
|
||||||
|
* `gcc my-vulkan-program.c frag_shader.o`
|
||||||
|
|
||||||
|
I wrote a hack to make shader compilation part of the build processess with meson:
|
||||||
|
```meson
|
||||||
|
compile_shader = find_program(meson.source_root() / 'compile-shader.sh')
|
||||||
|
shaders_gen = generator(
|
||||||
|
compile_shader,
|
||||||
|
output: '@PLAINNAME@.o',
|
||||||
|
arguments: [
|
||||||
|
'@BUILD_ROOT@',
|
||||||
|
'@INPUT@',
|
||||||
|
'@OUTPUT@',
|
||||||
|
'@PLAINNAME@',
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
sources += [
|
||||||
|
shaders_gen.process('shaders/shader.frag'),
|
||||||
|
shaders_gen.process('shaders/shader.vert')
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
`compile-shader.sh`:
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
build_root="$1"
|
||||||
|
src="$2"
|
||||||
|
obj="$3"
|
||||||
|
name="$4"
|
||||||
|
|
||||||
|
if [[ "$OSTYPE" == "msys" ]]; then
|
||||||
|
make_blob="$build_root/subprojects/make-coff-blob/blob-object-coff.exe"
|
||||||
|
else
|
||||||
|
make_blob="$build_root/subprojects/make-elf-blob/blob-object-elf"
|
||||||
|
fi
|
||||||
|
|
||||||
|
base_name="${name%.*}"
|
||||||
|
ext="${name#*.}"
|
||||||
|
|
||||||
|
spv="$obj.spv"
|
||||||
|
|
||||||
|
glslangValidator -V100 -o "$spv" "$src" && $make_blob "$obj" shaders "cg_${base_name}_${ext}" "$spv"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Caveats
|
||||||
|
* `blob-object-coff` is restricted to <4GB blobs because COFF is a 32-bit format
|
||||||
|
* `blob-object-elf` cannot be used on native Windows because it depends on POSIX
|
||||||
|
(fix: this program should use standard library headers instead of POSIX and bundle its own elf.h)
|
||||||
|
* both generators are hardcoded to generate object files flagged for x86_64 for their respective platforms
|
||||||
|
(fix: add an argument to select which platform to build for)
|
||||||
|
|
||||||
|
Fixing these things would be pretty trivial; feel free to send a PR.
|
||||||
|
I'd also be willing to do it myself if anyone ends up actually using this,
|
||||||
|
so you could open an issue instead too.
|
||||||
|
|
||||||
|
It'd also be nice to support Mach-O (MacOS) and combine both blob-object commands
|
||||||
|
into a single executable.
|
|
@ -0,0 +1,15 @@
|
||||||
|
project('blob-object', 'c', default_options: ['c_std=c17', 'warning_level=3'])
|
||||||
|
|
||||||
|
compiler = meson.get_compiler('c')
|
||||||
|
if compiler.get_id() == 'clang' or compiler.get_id() == 'gcc'
|
||||||
|
# MSVC does not support VLAs for us to disable them.
|
||||||
|
add_global_arguments('-Werror=vla', language: 'c')
|
||||||
|
endif
|
||||||
|
|
||||||
|
if target_machine.system() == 'windows'
|
||||||
|
add_global_arguments('-DUNICODE', '-D_CRT_SECURE_NO_WARNINGS', language: 'c')
|
||||||
|
else
|
||||||
|
# the ELF blob maker is not portable currently
|
||||||
|
subproject('blob-object-elf')
|
||||||
|
endif
|
||||||
|
subproject('blob-object-coff')
|
|
@ -0,0 +1,19 @@
|
||||||
|
project('blob-object-coff', 'c')
|
||||||
|
|
||||||
|
if meson.get_compiler('c').get_id() == 'msvc'
|
||||||
|
add_project_arguments(
|
||||||
|
# we must downcast a few things because COFF is 32-bit
|
||||||
|
'/IGNORE:4267',
|
||||||
|
language: 'c'
|
||||||
|
)
|
||||||
|
else
|
||||||
|
add_project_arguments(
|
||||||
|
'-Wno-pointer-arith',
|
||||||
|
'-Wno-sign-compare',
|
||||||
|
'-Wno-missing-braces',
|
||||||
|
'-fno-strict-aliasing',
|
||||||
|
language: 'c'
|
||||||
|
)
|
||||||
|
endif
|
||||||
|
|
||||||
|
make_coff_blob = executable('blob-object-coff', 'src/main.c', install: true)
|
|
@ -0,0 +1,51 @@
|
||||||
|
#ifndef _COFF_H
|
||||||
|
#define _COFF_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct coff_header {
|
||||||
|
uint16_t magic;
|
||||||
|
uint16_t nscns; /* number of sections */
|
||||||
|
uint32_t timdat; /* time and date stamp */
|
||||||
|
uint32_t symptr; /* file offset of symbol table */
|
||||||
|
uint32_t nsyms; /* number of symbols */
|
||||||
|
uint16_t opthdr; /* size of optional header */
|
||||||
|
uint16_t flags; /* flags */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MAGIC_AMD64 0x8664
|
||||||
|
|
||||||
|
struct coff_section {
|
||||||
|
char name[8]; /* section name */
|
||||||
|
uint32_t paddr; /* physical address */
|
||||||
|
uint32_t vaddr; /* virtual address */
|
||||||
|
uint32_t size; /* section size in bytes */
|
||||||
|
uint32_t scnptr; /* file offset to section data */
|
||||||
|
uint32_t relptr; /* file offset to relocation table */
|
||||||
|
uint32_t lnnoptr; /* file offset to line number table */
|
||||||
|
uint16_t nreloc; /* number of relocation table entries */
|
||||||
|
uint16_t nlnno; /* number of line number table entries */
|
||||||
|
uint32_t flags; /* section flags */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* section types */
|
||||||
|
#define STYP_TEXT 0x0020
|
||||||
|
#define STYP_DATA 0x0040
|
||||||
|
#define STYP_BSS 0x0080
|
||||||
|
|
||||||
|
struct coff_symtab {
|
||||||
|
uint32_t zeroes; /* must be zero; used as part of a feature we don't care about */
|
||||||
|
uint32_t name; /* offset into the string table */
|
||||||
|
uint32_t value;
|
||||||
|
uint16_t scnum; /* section number */
|
||||||
|
uint16_t type;
|
||||||
|
uint8_t sclass; /* storage class */
|
||||||
|
uint8_t numaux; /* auxiliary count */
|
||||||
|
};
|
||||||
|
#define COFF_SYMTAB_SIZE 18
|
||||||
|
|
||||||
|
/* symbol storage classes */
|
||||||
|
#define C_EXT 2 /* global symbol storage class */
|
||||||
|
#define C_STAT 3 /* static symbol storage class */
|
||||||
|
|
||||||
|
#endif /* _COFF_H */
|
|
@ -0,0 +1,174 @@
|
||||||
|
#ifndef _WIN32
|
||||||
|
#include <errno.h>
|
||||||
|
#endif
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "coff.h"
|
||||||
|
|
||||||
|
static const char* const usage =
|
||||||
|
"usage: blob-object-coff <output file> <section name> <symbol name> <blob file>\n";
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
if (argc < 5) {
|
||||||
|
fprintf(stderr, "not enough arguments\n%s", usage);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (argc > 5) {
|
||||||
|
fprintf(stderr, "too many arguments\n%s", usage);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* output_file_name = argv[1];
|
||||||
|
char* section_name = argv[2];
|
||||||
|
uint32_t section_name_size = strlen(section_name);
|
||||||
|
char* symbol_name = argv[3];
|
||||||
|
uint32_t symbol_name_size = strlen(symbol_name) + 1;
|
||||||
|
char* blob_file_name = argv[4];
|
||||||
|
|
||||||
|
if (section_name_size > 8) {
|
||||||
|
fprintf(stderr, "section name is too long for COFF\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE* blob_file = fopen(blob_file_name, "rb");
|
||||||
|
if (blob_file == NULL) {
|
||||||
|
goto blob_fail;
|
||||||
|
}
|
||||||
|
if (fseek(blob_file, 0, SEEK_END) != 0) {
|
||||||
|
goto blob_fail;
|
||||||
|
}
|
||||||
|
long blob_size = ftell(blob_file);
|
||||||
|
if (blob_size == -1L) {
|
||||||
|
goto blob_fail;
|
||||||
|
}
|
||||||
|
rewind(blob_file);
|
||||||
|
void* blob = malloc(blob_size);
|
||||||
|
if (fread(blob, 1, blob_size, blob_file) < blob_size) {
|
||||||
|
goto blob_fail;
|
||||||
|
}
|
||||||
|
fclose(blob_file);
|
||||||
|
|
||||||
|
FILE* output_file = fopen(output_file_name, "wb");
|
||||||
|
if (output_file == NULL) {
|
||||||
|
goto output_fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t size_name_size = symbol_name_size + 5;
|
||||||
|
uint32_t blob_name_size = symbol_name_size;
|
||||||
|
|
||||||
|
uint32_t strtab_size_name_off = 4;
|
||||||
|
uint32_t strtab_blob_name_off = strtab_size_name_off + size_name_size;
|
||||||
|
uint32_t strtab_size = 4 + strtab_blob_name_off + blob_name_size;
|
||||||
|
|
||||||
|
uint32_t coff_header_off = 0;
|
||||||
|
uint32_t section_header_off = sizeof(struct coff_header);
|
||||||
|
uint32_t symbol_header_off = section_header_off + sizeof(struct coff_section);
|
||||||
|
uint32_t size_symbol_off = symbol_header_off;
|
||||||
|
uint32_t blob_symbol_off = size_symbol_off + COFF_SYMTAB_SIZE;
|
||||||
|
uint32_t string_table_off = blob_symbol_off + COFF_SYMTAB_SIZE;
|
||||||
|
uint32_t blob_size_off = string_table_off + strtab_size;
|
||||||
|
uint32_t blob_data_off = blob_size_off + sizeof(uint64_t);
|
||||||
|
uint32_t file_end_off = blob_data_off + blob_size;
|
||||||
|
|
||||||
|
uint8_t* data = calloc(file_end_off, 1);
|
||||||
|
|
||||||
|
time_t now = time(0);
|
||||||
|
*(struct coff_header*) (data + coff_header_off) = (struct coff_header) {
|
||||||
|
.magic = MAGIC_AMD64,
|
||||||
|
.nscns = 1,
|
||||||
|
.timdat = (uint32_t) now,
|
||||||
|
.symptr = symbol_header_off,
|
||||||
|
.nsyms = 2,
|
||||||
|
.opthdr = 0,
|
||||||
|
.flags = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct coff_section data_section = {
|
||||||
|
.name = 0,
|
||||||
|
.paddr = 0,
|
||||||
|
.vaddr = 0,
|
||||||
|
.size = sizeof(uint64_t) + blob_size,
|
||||||
|
.scnptr = blob_size_off,
|
||||||
|
.relptr = 0,
|
||||||
|
.lnnoptr = 0,
|
||||||
|
.nreloc = 0,
|
||||||
|
.nlnno = 0,
|
||||||
|
.flags = STYP_DATA,
|
||||||
|
};
|
||||||
|
strncpy(data_section.name, section_name, section_name_size);
|
||||||
|
memcpy(data + section_header_off, &data_section, sizeof(struct coff_section));
|
||||||
|
|
||||||
|
struct coff_symtab size_symbol = {
|
||||||
|
.zeroes = 0,
|
||||||
|
.name = strtab_size_name_off,
|
||||||
|
.value = 0,
|
||||||
|
.scnum = 1,
|
||||||
|
.type = 0,
|
||||||
|
.sclass = C_EXT,
|
||||||
|
.numaux = 0,
|
||||||
|
};
|
||||||
|
memcpy(data + size_symbol_off, &size_symbol, COFF_SYMTAB_SIZE);
|
||||||
|
|
||||||
|
struct coff_symtab blob_symbol = {
|
||||||
|
.zeroes = 0,
|
||||||
|
.name = strtab_blob_name_off,
|
||||||
|
.value = sizeof(uint64_t),
|
||||||
|
.scnum = 1,
|
||||||
|
.type = 0,
|
||||||
|
.sclass = C_EXT,
|
||||||
|
.numaux = 0,
|
||||||
|
};
|
||||||
|
memcpy(data + blob_symbol_off, &blob_symbol, COFF_SYMTAB_SIZE);
|
||||||
|
|
||||||
|
memcpy(data + string_table_off, &strtab_size, 4);
|
||||||
|
memcpy(
|
||||||
|
data + string_table_off + strtab_size_name_off,
|
||||||
|
symbol_name,
|
||||||
|
size_name_size - 1
|
||||||
|
);
|
||||||
|
memcpy(
|
||||||
|
data + string_table_off + strtab_size_name_off + symbol_name_size - 1,
|
||||||
|
"_size\0",
|
||||||
|
6
|
||||||
|
);
|
||||||
|
memcpy(
|
||||||
|
data + string_table_off + strtab_blob_name_off,
|
||||||
|
symbol_name,
|
||||||
|
blob_name_size
|
||||||
|
);
|
||||||
|
|
||||||
|
*(uint64_t*) (data + blob_size_off) = blob_size;
|
||||||
|
memcpy(data + blob_data_off, blob, blob_size);
|
||||||
|
|
||||||
|
if (fwrite(data, 1, file_end_off, output_file) < file_end_off) {
|
||||||
|
goto output_fail;
|
||||||
|
}
|
||||||
|
if (fflush(output_file) != 0) {
|
||||||
|
goto output_fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
blob_fail:
|
||||||
|
fprintf(
|
||||||
|
stderr,
|
||||||
|
"failed to read blob file %s: %s\n%s",
|
||||||
|
blob_file_name,
|
||||||
|
strerror(errno),
|
||||||
|
usage
|
||||||
|
);
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
output_fail:
|
||||||
|
fprintf(
|
||||||
|
stderr,
|
||||||
|
"failed to write output file %s: %s\n %s",
|
||||||
|
output_file_name,
|
||||||
|
strerror(errno),
|
||||||
|
usage
|
||||||
|
);
|
||||||
|
return 1;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
project('blob-object-elf', 'c')
|
||||||
|
|
||||||
|
add_project_arguments('-Wno-pointer-arith', '-fno-strict-aliasing', language: 'c')
|
||||||
|
|
||||||
|
executable('blob-object-elf', 'src/main.c', install: true)
|
|
@ -0,0 +1,266 @@
|
||||||
|
#define _POSIX_C_SOURCE 200112L
|
||||||
|
|
||||||
|
#include <elf.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#ifndef align_up
|
||||||
|
#define align_up(num, align) (((num) + ((align)-1)) & ~((align)-1))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const char* const usage =
|
||||||
|
"usage: blob-object-elf <output file> <section name> <symbol name> <blob file>\n";
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
if (argc < 5) {
|
||||||
|
fprintf(stderr, "not enough arguments\n%s", usage);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (argc > 5) {
|
||||||
|
fprintf(stderr, "too many arguments\n%s", usage);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* output_file_name = argv[1];
|
||||||
|
char* section_name = argv[2];
|
||||||
|
size_t section_name_size = strlen(section_name) + 1;
|
||||||
|
char* symbol_name = argv[3];
|
||||||
|
size_t symbol_name_size = strlen(symbol_name) + 1;
|
||||||
|
char* blob_file_name = argv[4];
|
||||||
|
|
||||||
|
int blob_fd = open(blob_file_name, O_RDONLY);
|
||||||
|
if (blob_fd < 0) {
|
||||||
|
fprintf(
|
||||||
|
stderr,
|
||||||
|
"failed to open blob file %s: %s\n%s",
|
||||||
|
output_file_name,
|
||||||
|
strerror(errno),
|
||||||
|
usage
|
||||||
|
);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
off_t blob_size = lseek(blob_fd, 0, SEEK_END);
|
||||||
|
if (blob_size == (off_t) -1) {
|
||||||
|
fprintf(
|
||||||
|
stderr,
|
||||||
|
"failed to get size of blob file: %s\n",
|
||||||
|
strerror(errno)
|
||||||
|
);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* blob =
|
||||||
|
mmap((void*) -1, blob_size, PROT_READ, MAP_PRIVATE, blob_fd, 0);
|
||||||
|
if (blob == (void*) -1) {
|
||||||
|
fprintf(stderr, "failed to mmap blob file: %s\n", strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(blob_fd);
|
||||||
|
|
||||||
|
// only write is needed, but mmap requires O_RDWR
|
||||||
|
int output_fd = open(output_file_name, O_RDWR | O_CREAT | O_TRUNC);
|
||||||
|
if (output_fd < 0) {
|
||||||
|
fprintf(
|
||||||
|
stderr,
|
||||||
|
"failed to open output file %s: %s\n%s",
|
||||||
|
output_file_name,
|
||||||
|
strerror(errno),
|
||||||
|
usage
|
||||||
|
);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Pre-calculate file layout. It looks like this:
|
||||||
|
// * ELF header
|
||||||
|
// * Section headers:
|
||||||
|
// * .shstrtab
|
||||||
|
// * .strtab
|
||||||
|
// * .symtab
|
||||||
|
// * <blob-section>
|
||||||
|
// * .shstrtab data
|
||||||
|
// * .strtab data
|
||||||
|
// * .symtab data
|
||||||
|
// * <blob>_size
|
||||||
|
// * <blob>
|
||||||
|
//
|
||||||
|
|
||||||
|
char* shstrtab_fixed_data = "\0.shstrtab\0.strtab\0.symtab\0";
|
||||||
|
// offsets into .shstrtab
|
||||||
|
size_t shstrtab_shstrtab_off = 1;
|
||||||
|
size_t shstrtab_strtab_off = 11;
|
||||||
|
size_t shstrtab_symtab_off = 19;
|
||||||
|
size_t shstrtab_blob_off = 28;
|
||||||
|
size_t shstrtab_fixed_data_size = 28;
|
||||||
|
size_t shstrtab_data_size = shstrtab_fixed_data_size + section_name_size;
|
||||||
|
|
||||||
|
// offsets into .strtab
|
||||||
|
size_t strtab_name_off = 1;
|
||||||
|
size_t strtab_size_off = strtab_name_off + symbol_name_size;
|
||||||
|
size_t strtab_end_off = strtab_size_off + symbol_name_size + 5;
|
||||||
|
|
||||||
|
// three symbols: the zero symbol, the blob, and the blob size
|
||||||
|
size_t symtab_data_size = 3 * sizeof(Elf64_Sym);
|
||||||
|
|
||||||
|
// the absolute offsets into the file of each section as described above
|
||||||
|
Elf64_Off ehdr_off = 0;
|
||||||
|
Elf64_Off shtab_off = ehdr_off + sizeof(Elf64_Ehdr);
|
||||||
|
Elf64_Off shstrtab_hdr_off = shtab_off + sizeof(Elf64_Shdr);
|
||||||
|
Elf64_Off strtab_hdr_off = shstrtab_hdr_off + sizeof(Elf64_Shdr);
|
||||||
|
Elf64_Off symtab_hdr_off = strtab_hdr_off + sizeof(Elf64_Shdr);
|
||||||
|
Elf64_Off blob_hdr_off = symtab_hdr_off + sizeof(Elf64_Shdr);
|
||||||
|
Elf64_Off shstrtab_data_off = blob_hdr_off + sizeof(Elf64_Shdr);
|
||||||
|
Elf64_Off strtab_data_off = shstrtab_data_off + shstrtab_data_size;
|
||||||
|
Elf64_Off strtab_data_name_off = strtab_data_off + strtab_name_off;
|
||||||
|
Elf64_Off strtab_data_size_off = strtab_data_off + strtab_size_off;
|
||||||
|
Elf64_Off symtab_data_off = strtab_data_off + strtab_end_off;
|
||||||
|
Elf64_Off blob_size_off = symtab_data_off + symtab_data_size;
|
||||||
|
Elf64_Off blob_data_off = blob_size_off + sizeof(uint64_t);
|
||||||
|
Elf64_Off file_end_off = blob_data_off + blob_size;
|
||||||
|
|
||||||
|
if (ftruncate(output_fd, file_end_off) != 0) {
|
||||||
|
fprintf(
|
||||||
|
stderr,
|
||||||
|
"failed to truncate output file to size: %s\n",
|
||||||
|
strerror(errno)
|
||||||
|
);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* data =
|
||||||
|
mmap((void*) -1, file_end_off, PROT_WRITE, MAP_SHARED, output_fd, 0);
|
||||||
|
if (data == (void*) -1) {
|
||||||
|
fprintf(
|
||||||
|
stderr,
|
||||||
|
"failed to mmap output file: %s\n",
|
||||||
|
strerror(errno)
|
||||||
|
);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(output_fd);
|
||||||
|
|
||||||
|
*(Elf64_Ehdr*) (data + ehdr_off) = (Elf64_Ehdr) {
|
||||||
|
.e_ident = { 0x7F, 'E', 'L', 'F', ELFCLASS64, ELFDATA2LSB, EV_CURRENT },
|
||||||
|
.e_type = ET_REL,
|
||||||
|
.e_machine = EM_X86_64,
|
||||||
|
.e_version = EV_CURRENT,
|
||||||
|
.e_entry = 0,
|
||||||
|
.e_phoff = 0,
|
||||||
|
.e_shoff = shtab_off,
|
||||||
|
.e_flags = 0,
|
||||||
|
.e_ehsize = sizeof(Elf64_Ehdr),
|
||||||
|
.e_phentsize = 0,
|
||||||
|
.e_phnum = 0,
|
||||||
|
.e_shentsize = sizeof(Elf64_Shdr),
|
||||||
|
.e_shnum = 5,
|
||||||
|
.e_shstrndx = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
*(Elf64_Shdr*) (data + shstrtab_hdr_off) = (Elf64_Shdr) {
|
||||||
|
.sh_name = shstrtab_shstrtab_off,
|
||||||
|
.sh_type = SHT_STRTAB,
|
||||||
|
.sh_flags = 0,
|
||||||
|
.sh_addr = 0,
|
||||||
|
.sh_offset = shstrtab_data_off,
|
||||||
|
.sh_size = shstrtab_data_size,
|
||||||
|
.sh_link = 0,
|
||||||
|
.sh_info = 0,
|
||||||
|
.sh_addralign = 0,
|
||||||
|
.sh_entsize = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
*(Elf64_Shdr*) (data + strtab_hdr_off) = (Elf64_Shdr) {
|
||||||
|
.sh_name = shstrtab_strtab_off,
|
||||||
|
.sh_type = SHT_STRTAB,
|
||||||
|
.sh_flags = 0,
|
||||||
|
.sh_addr = 0,
|
||||||
|
.sh_offset = strtab_data_off,
|
||||||
|
.sh_size = strtab_end_off,
|
||||||
|
.sh_link = 0,
|
||||||
|
.sh_info = 0,
|
||||||
|
.sh_addralign = 0,
|
||||||
|
.sh_entsize = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
*(Elf64_Shdr*) (data + symtab_hdr_off) = (Elf64_Shdr) {
|
||||||
|
.sh_name = shstrtab_symtab_off,
|
||||||
|
.sh_type = SHT_SYMTAB,
|
||||||
|
.sh_flags = 0,
|
||||||
|
.sh_addr = 0,
|
||||||
|
.sh_offset = symtab_data_off,
|
||||||
|
.sh_size = symtab_data_size,
|
||||||
|
.sh_link = 2,
|
||||||
|
.sh_info = 1,
|
||||||
|
.sh_addralign = 0,
|
||||||
|
.sh_entsize = sizeof(Elf64_Sym),
|
||||||
|
};
|
||||||
|
|
||||||
|
*(Elf64_Shdr*) (data + blob_hdr_off) = (Elf64_Shdr) {
|
||||||
|
.sh_name = shstrtab_blob_off,
|
||||||
|
.sh_type = SHT_PROGBITS,
|
||||||
|
.sh_flags = SHF_ALLOC,
|
||||||
|
.sh_addr = 0,
|
||||||
|
.sh_offset = blob_size_off,
|
||||||
|
.sh_size = sizeof(uint64_t) + blob_size,
|
||||||
|
.sh_link = 0,
|
||||||
|
.sh_info = 0,
|
||||||
|
.sh_addralign = 0,
|
||||||
|
.sh_entsize = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
memcpy(
|
||||||
|
data + shstrtab_data_off,
|
||||||
|
shstrtab_fixed_data,
|
||||||
|
shstrtab_fixed_data_size
|
||||||
|
);
|
||||||
|
memcpy(
|
||||||
|
data + shstrtab_data_off + shstrtab_fixed_data_size,
|
||||||
|
section_name,
|
||||||
|
section_name_size
|
||||||
|
);
|
||||||
|
|
||||||
|
memcpy(data + strtab_data_name_off, symbol_name, symbol_name_size);
|
||||||
|
memcpy(
|
||||||
|
data + strtab_data_size_off,
|
||||||
|
symbol_name,
|
||||||
|
symbol_name_size - 1
|
||||||
|
);
|
||||||
|
memcpy(
|
||||||
|
data + strtab_data_size_off + symbol_name_size - 1,
|
||||||
|
"_size",
|
||||||
|
5
|
||||||
|
);
|
||||||
|
|
||||||
|
*(Elf64_Sym*) (data + symtab_data_off + sizeof(Elf64_Sym)) = (Elf64_Sym) {
|
||||||
|
.st_name = strtab_name_off,
|
||||||
|
.st_info = ELF64_ST_INFO(STB_GLOBAL, STT_OBJECT),
|
||||||
|
.st_other = ELF64_ST_VISIBILITY(STV_DEFAULT),
|
||||||
|
.st_shndx = 4,
|
||||||
|
.st_value = sizeof(uint64_t),
|
||||||
|
.st_size = blob_size,
|
||||||
|
};
|
||||||
|
|
||||||
|
// I wanted to make this an absolute symbol,
|
||||||
|
// but it segfaulted for whatever reason, probably relocation-related.
|
||||||
|
*(Elf64_Sym*) (data + symtab_data_off + 2 * sizeof(Elf64_Sym)) = (Elf64_Sym) {
|
||||||
|
.st_name = strtab_size_off,
|
||||||
|
.st_info = ELF64_ST_INFO(STB_GLOBAL, STT_OBJECT),
|
||||||
|
.st_other = ELF64_ST_VISIBILITY(STV_DEFAULT),
|
||||||
|
.st_shndx = 4,
|
||||||
|
.st_value = 0,
|
||||||
|
.st_size = sizeof(uint64_t),
|
||||||
|
};
|
||||||
|
|
||||||
|
*(uint64_t*) (data + blob_size_off) = blob_size;
|
||||||
|
memcpy(data + blob_data_off, blob, blob_size);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue