2021-07-25 21:14:27 +02:00
|
|
|
#include <stdarg.h>
|
2021-10-17 11:33:01 +02:00
|
|
|
#include <stddef.h>
|
2021-02-05 19:51:07 +01:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#define EPEP_INST
|
|
|
|
#include "epep/epep.h"
|
|
|
|
|
2021-06-27 01:24:45 +02:00
|
|
|
const char *epep_errors[] = {
|
|
|
|
"EPEP_ERR_SUCCESS",
|
|
|
|
"EPEP_ERR_DATA_DIRECTORY_INDEX_IS_INVALID",
|
|
|
|
"EPEP_ERR_SECTION_HEADER_INDEX_IS_INVALID",
|
|
|
|
"EPEP_ERR_SYMBOL_INDEX_IS_INVALID",
|
|
|
|
"EPEP_ERR_NOT_AN_OBJECT",
|
|
|
|
"EPEP_ERR_ADDRESS_IS_OUT_OF_SECTION_RAW_DATA",
|
|
|
|
"EPEP_ERR_OUTPUT_CAPACITY_IS_ZERO",
|
|
|
|
"EPEP_ERR_OUTPUT_IS_NULL",
|
|
|
|
"EPEP_ERR_ADDRESS_IS_OUT_OF_ANY_SECTION",
|
|
|
|
"EPEP_ERR_EXPORT_ADDRESS_TABLE_ENTRY_NAME_NOT_FOUND",
|
|
|
|
"EPEP_ERR_NO_BASE_RELOCATION_TABLE",
|
|
|
|
"EPEP_ERR_BASE_RELOCATION_IS_ALREADY_END",
|
|
|
|
"EPEP_ERR_INVALID_DATA_DIRECTORY_OFFSET",
|
|
|
|
"EPEP_ERR_INVALID_SECTION_HEADER_OFFSET",
|
|
|
|
"EPEP_ERR_INVALID_SECTION_DATA_OFFSET",
|
|
|
|
"EPEP_ERR_INVALID_STRING_TABLE_SIZE_OFFSET",
|
|
|
|
"EPEP_ERR_INVALID_SYMBOL_OFFSET",
|
|
|
|
"EPEP_ERR_INVALID_IMPORT_DIRECTORY_OFFSET",
|
|
|
|
"EPEP_ERR_INVALID_IMPORT_DIRECTORY_NAME_OFFSET",
|
|
|
|
"EPEP_ERR_INVALID_LOOKUP_OFFSET",
|
|
|
|
"EPEP_ERR_INVALID_LOOKUP_NAME_OFFSET",
|
|
|
|
"EPEP_ERR_INVALID_EXPORT_TABLE_OFFSET",
|
|
|
|
"EPEP_ERR_INVALID_DLL_NAME_OFFSET",
|
|
|
|
"EPEP_ERR_INVALID_EXPORT_NAME_POINTER_OFFSET",
|
|
|
|
"EPEP_ERR_INVALID_ORDINAL_TABLE_OFFSET",
|
|
|
|
"EPEP_ERR_INVALID_EXPORT_NAME_OFFSET",
|
|
|
|
"EPEP_ERR_INVALID_EXPORT_ADDRESS_OFFSET",
|
|
|
|
"EPEP_ERR_INVALID_FORWARDER_OFFSET",
|
|
|
|
"EPEP_ERR_INVALID_BASE_RELOCATION_BLOCK_OFFSET",
|
|
|
|
"EPEP_ERR_INVALID_NEXT_BASE_RELOCATION_BLOCK_OFFSET",
|
|
|
|
"EPEP_ERR_INVALID_BASE_RELOCATION_BLOCK_BASE_RELOCATION_OFFSET",
|
|
|
|
"EPEP_ERR_INVALID_SECTION_RELOCATION_OFFSET",
|
|
|
|
"EPEP_ERR_INVALID_LINENUMBER_OFFSET",
|
|
|
|
};
|
|
|
|
|
2021-02-05 19:51:07 +01:00
|
|
|
typedef char *pchar;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
Epep epep;
|
|
|
|
char *name;
|
|
|
|
size_t *section_offsets;
|
|
|
|
} CoffObject;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
size_t obj_id;
|
|
|
|
size_t sec_id;
|
|
|
|
} ObjIdSecId;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
ObjIdSecId *source;
|
|
|
|
uint32_t characteristics;
|
|
|
|
size_t size;
|
|
|
|
size_t number_of_relocations;
|
|
|
|
} SectionInfo;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
EpepCoffSymbol sym;
|
|
|
|
EpepCoffSymbol *auxes;
|
|
|
|
char *name;
|
|
|
|
size_t object_index;
|
|
|
|
size_t index;
|
|
|
|
} Symbol;
|
|
|
|
|
|
|
|
#define CDICT_VAL_T SectionInfo
|
|
|
|
#define CDICT_INST
|
|
|
|
#include "cdict/cdict.h"
|
|
|
|
|
|
|
|
#define CDICT_VAL_T Symbol
|
|
|
|
#define CDICT_INST
|
|
|
|
#include "cdict/cdict.h"
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
CoffObject *objects;
|
|
|
|
char **section_names_set;
|
|
|
|
CDict_CStr_SectionInfo info_per_section;
|
|
|
|
CDict_CStr_Symbol symtab;
|
|
|
|
char **sym_name_set;
|
|
|
|
size_t number_of_symbols;
|
|
|
|
} ObjectIr;
|
|
|
|
|
|
|
|
#define CVEC_INST
|
|
|
|
#define CVEC_TYPE CoffObject
|
|
|
|
#include "cvec/cvec.h"
|
|
|
|
|
|
|
|
#define CVEC_INST
|
|
|
|
#define CVEC_TYPE size_t
|
|
|
|
#include "cvec/cvec.h"
|
|
|
|
|
|
|
|
#define CVEC_INST
|
|
|
|
#define CVEC_TYPE pchar
|
|
|
|
#include "cvec/cvec.h"
|
|
|
|
|
|
|
|
#define CVEC_INST
|
|
|
|
#define CVEC_TYPE char
|
|
|
|
#include "cvec/cvec.h"
|
|
|
|
|
|
|
|
#define CVEC_INST
|
|
|
|
#define CVEC_TYPE ObjIdSecId
|
|
|
|
#include "cvec/cvec.h"
|
|
|
|
|
|
|
|
#define CVEC_INST
|
|
|
|
#define CVEC_TYPE EpepCoffSymbol
|
|
|
|
#include "cvec/cvec.h"
|
|
|
|
|
2021-06-27 01:24:45 +02:00
|
|
|
#define ERROR_EPEP(epep) printf("Error: epep returned %u (%s) at "__FILE__":%u", \
|
|
|
|
(epep)->error_code, epep_errors[(epep)->error_code], __LINE__); exit(-1)
|
2021-02-05 19:51:07 +01:00
|
|
|
|
|
|
|
#define ERROR_CDICT(cdict) printf("Error: cdict returned %u at "__FILE__":%u", \
|
|
|
|
(cdict)->error_code, __LINE__); exit(-1);
|
|
|
|
|
2021-07-25 14:22:47 +02:00
|
|
|
static int emit_logs;
|
|
|
|
|
2021-07-25 21:14:27 +02:00
|
|
|
static void log_info(const char *fmt, ...) {
|
2021-07-25 14:22:47 +02:00
|
|
|
if (emit_logs) {
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
|
|
vprintf(fmt, ap);
|
|
|
|
va_end(ap);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-05 19:51:07 +01:00
|
|
|
static void fwrite8(FILE *f, uint8_t b) {
|
|
|
|
fputc(b, f);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void fwrite16(FILE *f, uint16_t w) {
|
|
|
|
fputc((w & 0x00ff) >> 0, f);
|
|
|
|
fputc((w & 0xff00) >> 8, f);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void fwrite32(FILE *f, uint32_t d) {
|
|
|
|
fputc((d & 0x000000ff) >> 0, f);
|
|
|
|
fputc((d & 0x0000ff00) >> 8, f);
|
|
|
|
fputc((d & 0x00ff0000) >> 16, f);
|
|
|
|
fputc((d & 0xff000000) >> 24, f);
|
|
|
|
}
|
|
|
|
|
|
|
|
static size_t strtab_add(char **strtab, char *str) {
|
|
|
|
size_t res = cvec_char_size(strtab);
|
|
|
|
|
|
|
|
for (char *p = str; *p; p++) {
|
|
|
|
cvec_char_push_back(strtab, *p);
|
|
|
|
}
|
|
|
|
cvec_char_push_back(strtab, '\0');
|
|
|
|
return res + 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
static size_t get_section_number(char ***section_names_set, char *sec_name) {
|
|
|
|
for (size_t i = 0; i < cvec_pchar_size(section_names_set); i++) {
|
|
|
|
char *it = cvec_pchar_at(section_names_set, i);
|
|
|
|
if (!strcmp(it, sec_name)) {
|
|
|
|
return i + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void add_name_to_set(char *sym_name, char ***set) {
|
|
|
|
for (size_t i = 0; i < cvec_pchar_size(set); i++) {
|
|
|
|
char *it = cvec_pchar_at(set, i);
|
|
|
|
if (!strcmp(it, sym_name)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cvec_pchar_push_back(set, sym_name);
|
|
|
|
}
|
|
|
|
|
2021-07-24 10:39:13 +02:00
|
|
|
static void build(ObjectIr *ir, const char *outname) {
|
|
|
|
FILE *out = fopen(outname, "wb");
|
2021-02-05 19:51:07 +01:00
|
|
|
char *strtab = cvec_char_new(1024);
|
|
|
|
size_t size_of_sections = 0;
|
|
|
|
size_t number_of_relocations = 0;
|
|
|
|
|
2021-07-25 14:22:47 +02:00
|
|
|
log_info("Calculating all sections size and relocations count... ");
|
2021-02-05 19:51:07 +01:00
|
|
|
for (size_t sec_i = 0; sec_i < cvec_pchar_size(&ir->section_names_set); sec_i++) {
|
|
|
|
char *name = ir->section_names_set[sec_i];
|
|
|
|
|
|
|
|
SectionInfo si = cdict_CStr_SectionInfo_get_v(&ir->info_per_section, name);
|
|
|
|
size_of_sections += si.size;
|
|
|
|
number_of_relocations += si.number_of_relocations;
|
|
|
|
}
|
2021-07-25 14:22:47 +02:00
|
|
|
log_info("Done: %u & %u\n", size_of_sections, number_of_relocations);
|
2021-02-05 19:51:07 +01:00
|
|
|
|
|
|
|
size_t fisrt_section_offset = 20 + 40 * cvec_pchar_size(&ir->section_names_set);
|
|
|
|
size_t offset_to_first_relocation = fisrt_section_offset + size_of_sections;
|
|
|
|
size_t offset_to_next_relocation = offset_to_first_relocation;
|
|
|
|
size_t next_section_offset = fisrt_section_offset;
|
|
|
|
|
|
|
|
size_t PointerToSymbolTable = fisrt_section_offset + size_of_sections + number_of_relocations * 10;
|
|
|
|
|
|
|
|
// COFF Header
|
2021-07-25 14:22:47 +02:00
|
|
|
log_info("Writing COFF header... ");
|
2021-02-05 19:51:07 +01:00
|
|
|
fwrite16(out, 0x14c); // Machine
|
|
|
|
fwrite16(out, cvec_pchar_size(&ir->section_names_set)); // NumberOfSections
|
|
|
|
fwrite32(out, 0); // TimeDataStamp
|
|
|
|
fwrite32(out, PointerToSymbolTable); // PointerToSymbolTable
|
|
|
|
fwrite32(out, ir->number_of_symbols); // NumberOfSymbols
|
|
|
|
fwrite16(out, 0); // SizeOfOptionalHeader
|
|
|
|
fwrite16(out, 0); // Characteristics
|
2021-07-25 14:22:47 +02:00
|
|
|
log_info("Done.\n");
|
2021-02-05 19:51:07 +01:00
|
|
|
|
|
|
|
// Section Headers
|
2021-07-25 14:22:47 +02:00
|
|
|
log_info("Writing section headers {\n");
|
2021-02-05 19:51:07 +01:00
|
|
|
for (size_t sec_i = 0; sec_i < cvec_pchar_size(&ir->section_names_set); sec_i++) {
|
|
|
|
char *name = ir->section_names_set[sec_i];
|
|
|
|
SectionInfo si = cdict_CStr_SectionInfo_get_v(&ir->info_per_section, name);
|
|
|
|
|
|
|
|
// Name
|
2021-07-25 14:22:47 +02:00
|
|
|
log_info(" Writing %s Section Header... ", name);
|
2021-02-05 19:51:07 +01:00
|
|
|
if (strlen(name) <= 8) {
|
|
|
|
for (size_t i = 0; i < 8; i++) {
|
|
|
|
size_t sl = strlen(name);
|
|
|
|
fwrite8(out, i < sl ? name[i] : '\0');
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fwrite8(out, '/');
|
|
|
|
|
|
|
|
size_t strtab_index = strtab_add(&strtab, name);
|
|
|
|
char numstr[8] = { 0 };
|
2021-10-17 11:33:01 +02:00
|
|
|
sprintf(numstr, "%lu", strtab_index);
|
2021-02-05 19:51:07 +01:00
|
|
|
fwrite(numstr, 1, 7, out);
|
|
|
|
}
|
|
|
|
fwrite32(out, 0); // VirtualSize
|
|
|
|
fwrite32(out, 0); // VirtualAddress
|
|
|
|
fwrite32(out, si.size); // SizeOfRawData
|
|
|
|
fwrite32(out, next_section_offset); // PointerToRawData
|
|
|
|
next_section_offset += si.size;
|
|
|
|
fwrite32(out, offset_to_next_relocation); // PointerToRelocations
|
|
|
|
offset_to_next_relocation += si.number_of_relocations * 10;
|
|
|
|
fwrite32(out, 0); // PointerToLinenumbers
|
|
|
|
fwrite16(out, si.number_of_relocations); // NumberOfRelocations
|
|
|
|
fwrite16(out, 0); // NumberOfLinenumbers
|
|
|
|
fwrite32(out, si.characteristics); // Characteristics
|
2021-07-25 14:22:47 +02:00
|
|
|
log_info("Done.\n");
|
2021-02-05 19:51:07 +01:00
|
|
|
}
|
2021-07-25 14:22:47 +02:00
|
|
|
log_info("}\n");
|
2021-02-05 19:51:07 +01:00
|
|
|
|
|
|
|
// Section data
|
2021-07-25 14:22:47 +02:00
|
|
|
log_info("Writing sections {\n");
|
2021-02-05 19:51:07 +01:00
|
|
|
for (size_t sec_i = 0; sec_i < cvec_pchar_size(&ir->section_names_set); sec_i++) {
|
|
|
|
char *name = ir->section_names_set[sec_i];
|
|
|
|
SectionInfo si = cdict_CStr_SectionInfo_get_v(&ir->info_per_section, name);
|
|
|
|
|
2021-07-25 14:22:47 +02:00
|
|
|
log_info(" Writing %s... ", name);
|
2021-02-05 19:51:07 +01:00
|
|
|
for (size_t i = 0; i < cvec_ObjIdSecId_size(&si.source); i++) {
|
|
|
|
ObjIdSecId id = cvec_ObjIdSecId_at(&si.source, i);
|
|
|
|
CoffObject *object = &ir->objects[id.obj_id];
|
|
|
|
Epep *epep = &object->epep;
|
|
|
|
|
|
|
|
EpepSectionHeader sh = { 0 };
|
|
|
|
if (!epep_get_section_header_by_index(epep, &sh, id.sec_id)) {
|
|
|
|
ERROR_EPEP(epep);
|
|
|
|
}
|
2021-02-28 16:28:03 +01:00
|
|
|
|
|
|
|
// If the section contains uninitialized data (BSS)
|
|
|
|
// it should be filled by zeroes
|
|
|
|
// Yes, current implementation emits BSS sections too
|
|
|
|
// cause KOS has no idea they should be allocated automatically
|
|
|
|
// cause FASM has no idea they should be generated without contents
|
|
|
|
// cause Tomasz Grysztar didn't care
|
|
|
|
char *buf = calloc(sh.SizeOfRawData, 1);
|
|
|
|
|
|
|
|
// Othervice it should be filled by its contents from source object
|
|
|
|
if (!(sh.Characteristics & 0x00000080)) {
|
|
|
|
if (!epep_get_section_contents(epep, &sh, buf)) {
|
|
|
|
ERROR_EPEP(epep);
|
|
|
|
}
|
2021-02-05 19:51:07 +01:00
|
|
|
}
|
2021-02-28 16:28:03 +01:00
|
|
|
|
2021-02-05 19:51:07 +01:00
|
|
|
fwrite(buf, 1, sh.SizeOfRawData, out);
|
|
|
|
}
|
2021-07-25 14:22:47 +02:00
|
|
|
log_info("Done.\n");
|
2021-02-05 19:51:07 +01:00
|
|
|
}
|
2021-07-25 14:22:47 +02:00
|
|
|
log_info("}\n");
|
2021-02-05 19:51:07 +01:00
|
|
|
|
|
|
|
// COFF Relocations
|
2021-06-28 20:09:04 +02:00
|
|
|
char **undefined_symbols = cvec_pchar_new(8);
|
|
|
|
|
2021-07-25 14:22:47 +02:00
|
|
|
log_info("Writing COFF Relocations {\n");
|
2021-02-05 19:51:07 +01:00
|
|
|
for (size_t sec_i = 0; sec_i < cvec_pchar_size(&ir->section_names_set); sec_i++) {
|
|
|
|
char *name = ir->section_names_set[sec_i];
|
|
|
|
SectionInfo si = cdict_CStr_SectionInfo_get_v(&ir->info_per_section, name);
|
|
|
|
|
2021-07-25 14:22:47 +02:00
|
|
|
log_info(" Writing relocations of %s {\n", name);
|
2021-02-05 19:51:07 +01:00
|
|
|
for (size_t i = 0; i < cvec_ObjIdSecId_size(&si.source); i++) {
|
|
|
|
ObjIdSecId id = cvec_ObjIdSecId_at(&si.source, i);
|
|
|
|
CoffObject *object = &ir->objects[id.obj_id];
|
|
|
|
Epep *epep = &object->epep;
|
|
|
|
|
|
|
|
size_t strtab_size = 0;
|
|
|
|
if (!epep_get_string_table_size(epep, &strtab_size)) {
|
|
|
|
ERROR_EPEP(epep);
|
|
|
|
}
|
|
|
|
|
|
|
|
char *obj_strtab = malloc(strtab_size);
|
|
|
|
if (!epep_get_string_table(epep, obj_strtab)) {
|
|
|
|
ERROR_EPEP(epep);
|
|
|
|
}
|
|
|
|
|
|
|
|
EpepSectionHeader sh = { 0 };
|
|
|
|
if (!epep_get_section_header_by_index(epep, &sh, id.sec_id)) {
|
|
|
|
ERROR_EPEP(epep);
|
|
|
|
}
|
|
|
|
for (size_t rel_i = 0; rel_i < sh.NumberOfRelocations; rel_i++) {
|
|
|
|
EpepCoffRelocation rel = { 0 };
|
|
|
|
|
|
|
|
if (!epep_get_section_relocation_by_index(epep, &sh, &rel, rel_i)) {
|
|
|
|
ERROR_EPEP(epep);
|
|
|
|
}
|
2021-07-25 14:22:47 +02:00
|
|
|
log_info(" { %02x, %02x, %02x }", rel.VirtualAddress, rel.SymbolTableIndex, rel.Type);
|
2021-02-05 19:51:07 +01:00
|
|
|
rel.VirtualAddress += object->section_offsets[sec_i];
|
|
|
|
{
|
|
|
|
size_t index = rel.SymbolTableIndex;
|
|
|
|
EpepCoffSymbol sym = { 0 };
|
|
|
|
|
|
|
|
if (!epep_get_symbol_by_index(epep, &sym, index)) {
|
|
|
|
ERROR_EPEP(epep);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t name_max = 1024;
|
|
|
|
char name[name_max];
|
|
|
|
|
|
|
|
if (sym.symbol.Zeroes == 0) {
|
|
|
|
strcpy(name, &obj_strtab[sym.symbol.Offset]);
|
|
|
|
} else {
|
|
|
|
memcpy(name, sym.symbol.ShortName, 8);
|
|
|
|
name[8] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(name, "_EXPORTS")) {
|
|
|
|
strcpy(name, "EXPORTS");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sym.symbol.StorageClass != 2) {
|
|
|
|
sprintf(name, "%s@%s", name, object->name);
|
|
|
|
}
|
|
|
|
|
|
|
|
Symbol old_sym = cdict_CStr_Symbol_get_v(&ir->symtab, name);
|
|
|
|
|
|
|
|
if (old_sym.name == NULL) {
|
2021-06-28 20:09:04 +02:00
|
|
|
add_name_to_set(strdup(name), &undefined_symbols);
|
2021-02-05 19:51:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
rel.SymbolTableIndex = old_sym.index;
|
2021-07-25 14:22:47 +02:00
|
|
|
log_info(" -> { %02x, %02x, %02x }: ", rel.VirtualAddress, rel.SymbolTableIndex, rel.Type);
|
|
|
|
log_info("New relocation of %s in %s\n", name, sh.Name);
|
2021-02-05 19:51:07 +01:00
|
|
|
}
|
|
|
|
fwrite(&rel, 1, 10, out);
|
|
|
|
}
|
|
|
|
}
|
2021-07-25 14:22:47 +02:00
|
|
|
log_info(" }\n");
|
2021-02-05 19:51:07 +01:00
|
|
|
}
|
2021-07-25 14:22:47 +02:00
|
|
|
log_info("}\n");
|
2021-02-05 19:51:07 +01:00
|
|
|
|
2021-06-28 20:09:04 +02:00
|
|
|
if (cvec_pchar_size(&undefined_symbols) > 0) {
|
|
|
|
printf("Undefined symbols found, aborting\nUndefined:\n");
|
|
|
|
for (int i = 0; i < cvec_pchar_size(&undefined_symbols); i++) {
|
|
|
|
printf("%s\n", undefined_symbols[i]);
|
|
|
|
}
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
2021-02-05 19:51:07 +01:00
|
|
|
// Symbols Table
|
2021-07-25 14:22:47 +02:00
|
|
|
log_info("Writing symbols {\n");
|
2021-02-05 19:51:07 +01:00
|
|
|
for (size_t sym_i = 0; sym_i < cvec_pchar_size(&ir->sym_name_set); sym_i++) {
|
|
|
|
char *name = ir->sym_name_set[sym_i];
|
|
|
|
|
|
|
|
Symbol sym = cdict_CStr_Symbol_get_v(&ir->symtab, name);
|
|
|
|
|
|
|
|
if (sym.sym.symbol.SectionNumber == 0xffff ||
|
|
|
|
sym.sym.symbol.SectionNumber == 0xfffe ||
|
2021-07-22 21:33:40 +02:00
|
|
|
(sym.sym.symbol.StorageClass != 2 && // Not an external symbol
|
|
|
|
sym.sym.symbol.StorageClass != 3 && // Not a static symbol
|
|
|
|
sym.sym.symbol.StorageClass != 6)) { // Not a label
|
2021-02-05 19:51:07 +01:00
|
|
|
fwrite(&sym.sym.symbol, 1, 18, out);
|
|
|
|
} else {
|
|
|
|
size_t sec_name_max = 1024;
|
|
|
|
char sec_name[sec_name_max];
|
|
|
|
|
|
|
|
size_t object_index = sym.object_index;
|
|
|
|
CoffObject *object = &ir->objects[object_index];
|
|
|
|
Epep *epep = &object->epep;
|
|
|
|
size_t section_offset = object->section_offsets[sym.sym.symbol.SectionNumber - 1];
|
|
|
|
|
|
|
|
size_t strtab_size = 0;
|
|
|
|
if (!epep_get_string_table_size(epep, &strtab_size)) {
|
|
|
|
ERROR_EPEP(epep);
|
|
|
|
}
|
|
|
|
|
|
|
|
char *obj_strtab = malloc(strtab_size);
|
|
|
|
if (!epep_get_string_table(epep, obj_strtab)) {
|
|
|
|
ERROR_EPEP(epep);
|
|
|
|
}
|
|
|
|
|
|
|
|
EpepSectionHeader sh = { 0 };
|
|
|
|
if (!epep_get_section_header_by_index(epep, &sh, sym.sym.symbol.SectionNumber - 1)) {
|
|
|
|
ERROR_EPEP(epep);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sh.Name[0] == '/') {
|
|
|
|
strcpy(sec_name, &obj_strtab[atoi(&sh.Name[1])]);
|
|
|
|
} else {
|
|
|
|
memcpy(sec_name, sh.Name, 8);
|
|
|
|
sec_name[8] = '\0';
|
|
|
|
}
|
|
|
|
|
2021-07-25 14:22:47 +02:00
|
|
|
log_info("%s:\n", sym.name);
|
|
|
|
log_info(" Section: %s\n", sec_name);
|
|
|
|
log_info(" StorageClass: %u\n", sym.sym.symbol.StorageClass);
|
2021-02-05 19:51:07 +01:00
|
|
|
|
|
|
|
sym.sym.symbol.SectionNumber = get_section_number(&ir->section_names_set, sec_name);
|
|
|
|
|
|
|
|
if (sym.sym.symbol.SectionNumber == 0) {
|
2021-07-25 21:14:27 +02:00
|
|
|
printf("Internal error: %s section is not found in output file", sec_name);
|
2021-02-05 19:51:07 +01:00
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
sym.sym.symbol.Value += section_offset;
|
|
|
|
|
|
|
|
if (strlen(sym.name) <= 8) {
|
2021-07-22 21:33:40 +02:00
|
|
|
memcpy(sym.sym.symbol.ShortName, sym.name, 8);
|
2021-02-05 19:51:07 +01:00
|
|
|
} else {
|
|
|
|
sym.sym.symbol.Zeroes = 0;
|
|
|
|
sym.sym.symbol.Offset = strtab_add(&strtab, name);
|
|
|
|
}
|
|
|
|
|
|
|
|
fwrite(&sym.sym.symbol, 1, 18, out);
|
|
|
|
}
|
|
|
|
for (size_t aux_i = 0; aux_i < sym.sym.symbol.NumberOfAuxSymbols; aux_i++) {
|
|
|
|
fwrite(&sym.auxes[aux_i].symbol, 1, 18, out);
|
|
|
|
}
|
|
|
|
}
|
2021-07-25 14:22:47 +02:00
|
|
|
log_info("}\n");
|
2021-02-05 19:51:07 +01:00
|
|
|
|
|
|
|
// COFF String Table
|
2021-07-25 14:22:47 +02:00
|
|
|
log_info("Writing COFF String Table... ");
|
2021-07-25 21:14:27 +02:00
|
|
|
fwrite32(out, cvec_char_size(&strtab) + 4);
|
|
|
|
fwrite(strtab, 1, cvec_char_size(&strtab), out);
|
2021-07-25 14:22:47 +02:00
|
|
|
log_info("Done.\n");
|
2021-02-05 19:51:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static ObjectIr parse_objects(int argc, char **argv) {
|
|
|
|
CoffObject *objects = cvec_CoffObject_new(128);
|
|
|
|
char **section_names_set = cvec_pchar_new(4);
|
|
|
|
char **sym_name_set = cvec_pchar_new(128);
|
|
|
|
size_t number_of_symbols = 0;
|
|
|
|
|
|
|
|
for (int i = 1; i < argc; i++) {
|
2021-07-25 14:22:47 +02:00
|
|
|
// If one arg is NULL, that means it was a parameter and was cleared
|
|
|
|
// It's not a input file name
|
|
|
|
if (argv[i] == NULL) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
log_info("Primary parsing of %s... ", argv[i]);
|
2021-02-05 19:51:07 +01:00
|
|
|
|
|
|
|
CoffObject object = { 0 };
|
|
|
|
object.name = argv[i];
|
|
|
|
object.section_offsets = cvec_size_t_new(128);
|
|
|
|
|
|
|
|
{
|
|
|
|
FILE *fp = fopen(object.name, "rb");
|
|
|
|
if (!fp) {
|
|
|
|
printf("Error: Can't open \"%s\"", object.name);
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!epep_init(&object.epep, fp)) {
|
|
|
|
ERROR_EPEP(&object.epep);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cvec_CoffObject_push_back(&objects, object);
|
|
|
|
|
2021-07-25 14:22:47 +02:00
|
|
|
log_info("Done.\n");
|
2021-02-05 19:51:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
CDict_CStr_Symbol symtab;
|
|
|
|
|
|
|
|
if (!cdict_CStr_Symbol_init(&symtab)) {
|
|
|
|
ERROR_CDICT(&symtab);
|
|
|
|
}
|
|
|
|
|
|
|
|
CDict_CStr_SectionInfo info_per_section;
|
|
|
|
|
|
|
|
if (!cdict_CStr_SectionInfo_init(&info_per_section)) {
|
|
|
|
ERROR_CDICT(&info_per_section);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i = 0; i < cvec_CoffObject_size(&objects); i++) {
|
2021-07-25 14:22:47 +02:00
|
|
|
log_info("Secondary parsing of %s {\n", objects[i].name);
|
2021-02-05 19:51:07 +01:00
|
|
|
|
|
|
|
Epep *epep = &(objects[i].epep);
|
|
|
|
|
|
|
|
size_t strtab_size = 0;
|
|
|
|
if (!epep_get_string_table_size(epep, &strtab_size)) {
|
|
|
|
ERROR_EPEP(epep);
|
|
|
|
}
|
|
|
|
|
|
|
|
char *strtab = malloc(strtab_size);
|
|
|
|
if (!epep_get_string_table(epep, strtab)) {
|
|
|
|
ERROR_EPEP(epep);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fill symbols table
|
2021-07-25 14:22:47 +02:00
|
|
|
log_info(" Symbols {\n");
|
2021-02-05 19:51:07 +01:00
|
|
|
for (size_t sym_i = 0; sym_i < epep->coffFileHeader.NumberOfSymbols; sym_i++) {
|
|
|
|
EpepCoffSymbol sym = { 0 };
|
|
|
|
|
|
|
|
if (!epep_get_symbol_by_index(epep, &sym, sym_i)) {
|
|
|
|
ERROR_EPEP(epep);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t name_max = 1024;
|
|
|
|
char name[name_max];
|
|
|
|
|
|
|
|
if (sym.symbol.Zeroes == 0) {
|
|
|
|
strcpy(name, &strtab[sym.symbol.Offset]);
|
|
|
|
} else {
|
|
|
|
memcpy(name, sym.symbol.ShortName, 8);
|
|
|
|
name[8] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(name, "_EXPORTS")) {
|
|
|
|
strcpy(name, "EXPORTS");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sym.symbol.StorageClass != 2) {
|
|
|
|
sprintf(name, "%s@%s", name, objects[i].name);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sym.symbol.StorageClass != 2 || sym.symbol.SectionNumber) {
|
|
|
|
if (memcmp(cdict_CStr_Symbol_get_v(&symtab, name).sym.symbol.ShortName, "\0\0\0\0\0\0\0\0", 8)) {
|
|
|
|
printf("Error: Redefinition of \"%s\"", name);
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
EpepCoffSymbol *auxes = cvec_EpepCoffSymbol_new(1);
|
|
|
|
size_t index = number_of_symbols;
|
|
|
|
|
|
|
|
for (size_t aux_i = 0; aux_i < sym.symbol.NumberOfAuxSymbols; aux_i++) {
|
|
|
|
EpepCoffSymbol aux = { 0 };
|
|
|
|
|
|
|
|
if (!epep_get_symbol_by_index(epep, &aux, sym_i + aux_i)) {
|
|
|
|
ERROR_EPEP(epep);
|
|
|
|
}
|
|
|
|
cvec_EpepCoffSymbol_push_back(&auxes, aux);
|
|
|
|
number_of_symbols++;
|
|
|
|
}
|
|
|
|
|
|
|
|
Symbol new_sym = { sym, auxes, strdup(name), i, index };
|
|
|
|
if (!cdict_CStr_Symbol_add_vv(&symtab, strdup(name), new_sym, CDICT_NO_CHECK)) {
|
|
|
|
ERROR_CDICT(&symtab);
|
|
|
|
}
|
|
|
|
number_of_symbols++;
|
|
|
|
|
2021-07-25 14:22:47 +02:00
|
|
|
log_info(" Symbol #%u: %s (%u auxes, #%u)\n", sym_i, name, cvec_EpepCoffSymbol_size(&auxes), number_of_symbols - 1);
|
2021-02-05 19:51:07 +01:00
|
|
|
|
|
|
|
add_name_to_set(strdup(name), &sym_name_set);
|
|
|
|
}
|
|
|
|
|
|
|
|
sym_i += sym.symbol.NumberOfAuxSymbols;
|
|
|
|
}
|
2021-07-25 14:22:47 +02:00
|
|
|
log_info(" }\n");
|
2021-02-05 19:51:07 +01:00
|
|
|
|
|
|
|
// Set section offsets and fill unique section name set
|
2021-07-25 14:22:47 +02:00
|
|
|
log_info(" Sections {\n");
|
2021-02-05 19:51:07 +01:00
|
|
|
for (size_t sec_i = 0; sec_i < epep->coffFileHeader.NumberOfSections; sec_i++) {
|
|
|
|
EpepSectionHeader sh = { 0 };
|
|
|
|
|
|
|
|
if (!epep_get_section_header_by_index(epep, &sh, sec_i)) {
|
|
|
|
ERROR_EPEP(epep);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t name_max = 1024;
|
|
|
|
char name[name_max];
|
|
|
|
|
|
|
|
if (sh.Name[0] == '/') {
|
|
|
|
strcpy(name, &strtab[atoi(&sh.Name[1])]);
|
|
|
|
} else {
|
|
|
|
memcpy(name, sh.Name, 8);
|
|
|
|
name[8] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
add_name_to_set(strdup(name), §ion_names_set);
|
|
|
|
|
|
|
|
SectionInfo si = cdict_CStr_SectionInfo_get_v(&info_per_section, name);
|
|
|
|
if (si.source == NULL) {
|
|
|
|
si.source = cvec_ObjIdSecId_new(32);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t sec_offset = si.size;
|
|
|
|
cvec_size_t_push_back(&objects[i].section_offsets, sec_offset);
|
|
|
|
|
|
|
|
si.size += sh.SizeOfRawData;
|
|
|
|
si.characteristics |= sh.Characteristics;
|
|
|
|
si.number_of_relocations += sh.NumberOfRelocations;
|
|
|
|
cvec_ObjIdSecId_push_back(&si.source, (ObjIdSecId){ i, sec_i });
|
|
|
|
cdict_CStr_SectionInfo_add_vv(&info_per_section, strdup(name), si, CDICT_REPLACE_EXIST);
|
|
|
|
|
2021-07-25 14:22:47 +02:00
|
|
|
log_info(" Section #%llu {\n", sec_i);
|
|
|
|
log_info(" Name: %s\n", name);
|
|
|
|
log_info(" Virtual Address: %u\n", sh.VirtualAddress);
|
|
|
|
log_info(" Characteristics: %08x\n", sh.Characteristics);
|
|
|
|
log_info(" Offset in the big section: %u\n", objects[i].section_offsets[sec_i]);
|
|
|
|
log_info(" }\n");
|
2021-07-22 21:33:40 +02:00
|
|
|
|
|
|
|
if (sh.VirtualAddress != 0) {
|
2021-07-25 14:22:47 +02:00
|
|
|
printf("Warning: Handling of section with Virtual Address another that 0 is not implemented");
|
2021-07-22 21:33:40 +02:00
|
|
|
}
|
2021-02-05 19:51:07 +01:00
|
|
|
}
|
2021-07-25 14:22:47 +02:00
|
|
|
log_info(" }\n");
|
|
|
|
log_info("}\n");
|
2021-02-05 19:51:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ObjectIr ir;
|
|
|
|
ir.objects = objects;
|
|
|
|
ir.section_names_set = section_names_set;
|
|
|
|
ir.info_per_section = info_per_section;
|
|
|
|
ir.symtab = symtab;
|
|
|
|
ir.sym_name_set = sym_name_set;
|
|
|
|
ir.number_of_symbols = number_of_symbols;
|
|
|
|
return ir;
|
|
|
|
}
|
|
|
|
|
2021-07-25 14:22:47 +02:00
|
|
|
int arg_got_flag(int argc, char **argv, ...) {
|
|
|
|
char *arg_names[8];
|
|
|
|
int arg_name_c = 0;
|
|
|
|
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, argv);
|
|
|
|
for (char *arg_name = va_arg(ap, char *); arg_name; arg_name = va_arg(ap, char *)) {
|
|
|
|
if (arg_name_c >= 8) {
|
|
|
|
printf("Internal error: Too many parameter aliases passed to %s", __func__);
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
arg_names[arg_name_c++] = arg_name;
|
|
|
|
}
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
for (int i = 1; i < argc; i++) {
|
2021-07-25 22:38:50 +02:00
|
|
|
// If an argumetns was handled already then it's NULL here
|
|
|
|
if (argv[i] == NULL) {
|
|
|
|
continue;
|
|
|
|
}
|
2021-07-25 14:22:47 +02:00
|
|
|
for (int arg_name_i = 0; arg_name_i < arg_name_c; arg_name_i++) {
|
|
|
|
char *arg_name = arg_names[arg_name_i];
|
|
|
|
if (!strcmp(argv[i], arg_name)) {
|
|
|
|
argv[i] = NULL; // Do not handle this argument as a input name
|
2021-07-25 22:38:50 +02:00
|
|
|
return i;
|
2021-07-25 14:22:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-07-25 22:38:50 +02:00
|
|
|
char *arg_got_param(int argc, char **argv, char *arg) {
|
|
|
|
int i = arg_got_flag(argc, argv, arg, 0);
|
|
|
|
if (i == 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i + 1 >= argc) {
|
|
|
|
printf("Warning: %s parameter expects a value (like %s <value>)", arg, arg);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
char *result = argv[i + 1];
|
|
|
|
argv[i + 1] = NULL;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
int usage(char *name, char *remark) {
|
|
|
|
if (remark) {
|
|
|
|
printf("Error: %s\n\n", remark);
|
|
|
|
}
|
|
|
|
printf("Usage: %s [option]... [object file name]...\n", name);
|
|
|
|
printf(" Link multiple COFF files into one\n");
|
|
|
|
printf("\n");
|
|
|
|
printf("Options:\n");
|
|
|
|
printf(" -o <outname> Output into <outname>\n");
|
|
|
|
printf(" -v, --verbose Emit information logs\n");
|
|
|
|
printf(" -h, --help Output this help and exit\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-02-05 19:51:07 +01:00
|
|
|
int main(int argc, char **argv) {
|
2021-07-25 22:38:50 +02:00
|
|
|
if (arg_got_flag(argc, argv, "-h", "-help", "--help", 0)) {
|
|
|
|
return usage(argv[0], NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *outname = arg_got_param(argc, argv, "-o");
|
|
|
|
if (outname == NULL) {
|
|
|
|
outname = "a.out.obj";
|
2021-07-24 10:39:13 +02:00
|
|
|
}
|
|
|
|
|
2021-07-25 14:22:47 +02:00
|
|
|
emit_logs = arg_got_flag(argc, argv, "-v", "-verbose", "--verbose", 0);
|
|
|
|
|
2021-07-25 22:38:50 +02:00
|
|
|
// After handling arguments there only leaven unhandled ones
|
|
|
|
// They should be names if inputs. But if there's no input - exit
|
|
|
|
int input_file_count = 0;
|
|
|
|
for (int i = 1; i < argc; i++) {
|
|
|
|
if (argv[i] != NULL) {
|
|
|
|
input_file_count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (input_file_count == 0) {
|
|
|
|
return usage(argv[0], "No input file names supplied");
|
|
|
|
}
|
|
|
|
|
2021-02-05 19:51:07 +01:00
|
|
|
ObjectIr ir = parse_objects(argc, argv);
|
2021-07-24 10:39:13 +02:00
|
|
|
build(&ir, outname);
|
2021-03-01 18:26:41 +01:00
|
|
|
return 0;
|
2021-02-05 19:51:07 +01:00
|
|
|
}
|