mirror of
https://github.com/zeldaret/oot.git
synced 2024-11-11 03:39:59 +00:00
Speed up build a bit (#341)
* Speed up elf2rom * Remove all built-in make rules * Only perform a single mkdir * Optimize elf2rom further Co-authored-by: zelda2774 <zelda2774@invalid>
This commit is contained in:
parent
dea5f4aae5
commit
281aaa0cb6
3 changed files with 58 additions and 68 deletions
5
Makefile
5
Makefile
|
@ -1,4 +1,4 @@
|
||||||
.SUFFIXES:
|
MAKEFLAGS += --no-builtin-rules
|
||||||
|
|
||||||
# Build options can either be changed by modifying the makefile, or by building with 'make SETTING=value'
|
# Build options can either be changed by modifying the makefile, or by building with 'make SETTING=value'
|
||||||
|
|
||||||
|
@ -109,8 +109,7 @@ O_FILES := $(foreach f,$(S_FILES:.s=.o),build/$f) \
|
||||||
# $(foreach f,$(TEXTURE_FILES_CI8:.ci8.png=.ci8),build/$f) \
|
# $(foreach f,$(TEXTURE_FILES_CI8:.ci8.png=.ci8),build/$f) \
|
||||||
|
|
||||||
# create build directories
|
# create build directories
|
||||||
$(shell mkdir -p build/baserom)
|
$(shell mkdir -p build/baserom $(foreach dir,$(SRC_DIRS) $(ASM_DIRS) $(TEXTURE_DIRS) $(TEXTURE_BIN_DIRS) $(SCENE_DIRS),build/$(dir)))
|
||||||
$(foreach dir,$(SRC_DIRS) $(ASM_DIRS) $(TEXTURE_DIRS) $(TEXTURE_BIN_DIRS) $(SCENE_DIRS),$(shell mkdir -p build/$(dir)))
|
|
||||||
|
|
||||||
build/src/libultra_boot_O1/%.o: OPTFLAGS := -O1
|
build/src/libultra_boot_O1/%.o: OPTFLAGS := -O1
|
||||||
build/src/libultra_boot_O2/%.o: OPTFLAGS := -O2
|
build/src/libultra_boot_O2/%.o: OPTFLAGS := -O2
|
||||||
|
|
115
tools/elf2rom.c
115
tools/elf2rom.c
|
@ -64,58 +64,58 @@ static struct RomSegment *add_rom_segment(const char *name)
|
||||||
|
|
||||||
g_romSegmentsCount++;
|
g_romSegmentsCount++;
|
||||||
g_romSegments = realloc(g_romSegments, g_romSegmentsCount * sizeof(*g_romSegments));
|
g_romSegments = realloc(g_romSegments, g_romSegmentsCount * sizeof(*g_romSegments));
|
||||||
|
|
||||||
g_romSegments[index].name = name;
|
g_romSegments[index].name = name;
|
||||||
g_romSegments[index].romStart = -1;
|
|
||||||
g_romSegments[index].romEnd = -1;
|
|
||||||
return &g_romSegments[index];
|
return &g_romSegments[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void find_segment_info(struct Elf32 *elf, struct RomSegment *segment)
|
static int find_symbol_value(struct Elf32_Symbol *syms, int numsymbols, const char *name)
|
||||||
{
|
{
|
||||||
int i;
|
struct Elf32_Symbol *sym;
|
||||||
char *romStartSymName = sprintf_alloc("_%sSegmentRomStart", segment->name);
|
int lo, hi, mid, cmp;
|
||||||
char *romEndSymName = sprintf_alloc("_%sSegmentRomEnd", segment->name);
|
|
||||||
|
|
||||||
segment->romStart = -1;
|
// Binary search for the symbol. We maintain the invariant that [lo, hi) is
|
||||||
segment->romEnd = -1;
|
// the interval that remains to search.
|
||||||
|
lo = 0;
|
||||||
// TODO: use a hashmap for this instead of an O(n) loop
|
hi = numsymbols;
|
||||||
for (i = 0; i < elf->numsymbols; i++)
|
while (lo < hi)
|
||||||
{
|
{
|
||||||
struct Elf32_Symbol sym;
|
mid = lo + (hi - lo) / 2;
|
||||||
|
sym = &syms[mid];
|
||||||
|
cmp = strcmp(sym->name, name);
|
||||||
|
|
||||||
if (!elf32_get_symbol(elf, &sym, i))
|
if (cmp == 0)
|
||||||
util_fatal_error("invalid or corrupt ELF file");
|
return (int) sym->value;
|
||||||
|
else if (cmp < 0)
|
||||||
if (strcmp(sym.name, romStartSymName) == 0)
|
lo = mid + 1;
|
||||||
{
|
else
|
||||||
segment->romStart = sym.value;
|
hi = mid;
|
||||||
if (segment->romEnd != -1)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (strcmp(sym.name, romEndSymName) == 0)
|
|
||||||
{
|
|
||||||
segment->romEnd = sym.value;
|
|
||||||
if (segment->romStart != -1)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (segment->romStart == -1)
|
util_fatal_error("Symbol %s is not defined\n", name);
|
||||||
util_fatal_error("ROM start address of %s is not defined\n", segment->name);
|
}
|
||||||
if (segment->romEnd == -1)
|
|
||||||
util_fatal_error("ROM end address of %s is not defined\n", segment->name);
|
|
||||||
|
|
||||||
free(romStartSymName);
|
static int find_rom_address(struct Elf32_Symbol *syms, int numsymbols, const char *name, const char *suffix)
|
||||||
free(romEndSymName);
|
{
|
||||||
|
char *symName = sprintf_alloc("_%sSegmentRom%s", name, suffix);
|
||||||
|
int ret = find_symbol_value(syms, numsymbols, symName);
|
||||||
|
free(symName);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmp_symbol_by_name(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
return strcmp(
|
||||||
|
((struct Elf32_Symbol *)a)->name,
|
||||||
|
((struct Elf32_Symbol *)b)->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parse_input_file(const char *filename)
|
static void parse_input_file(const char *filename)
|
||||||
{
|
{
|
||||||
struct Elf32 elf;
|
struct Elf32 elf;
|
||||||
|
struct Elf32_Symbol *syms;
|
||||||
const void *data;
|
const void *data;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
int numRomSymbols;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
data = util_read_whole_file(filename, &size);
|
data = util_read_whole_file(filename, &size);
|
||||||
|
@ -123,6 +123,19 @@ static void parse_input_file(const char *filename)
|
||||||
if (!elf32_init(&elf, data, size) || elf.machine != ELF_MACHINE_MIPS)
|
if (!elf32_init(&elf, data, size) || elf.machine != ELF_MACHINE_MIPS)
|
||||||
util_fatal_error("%s is not a valid 32-bit MIPS ELF file", filename);
|
util_fatal_error("%s is not a valid 32-bit MIPS ELF file", filename);
|
||||||
|
|
||||||
|
// sort all symbols that contain the substring "Rom" for fast access
|
||||||
|
// (sorting all symbols costs 0.1s, might as well avoid that)
|
||||||
|
syms = malloc(elf.numsymbols * sizeof(struct Elf32_Symbol));
|
||||||
|
numRomSymbols = 0;
|
||||||
|
for (i = 0; i < elf.numsymbols; i++)
|
||||||
|
{
|
||||||
|
if (!elf32_get_symbol(&elf, &syms[numRomSymbols], i))
|
||||||
|
util_fatal_error("invalid or corrupt ELF file");
|
||||||
|
if (strstr(syms[numRomSymbols].name, "Rom"))
|
||||||
|
numRomSymbols++;
|
||||||
|
}
|
||||||
|
qsort(syms, numRomSymbols, sizeof(struct Elf32_Symbol), cmp_symbol_by_name);
|
||||||
|
|
||||||
// get ROM segments
|
// get ROM segments
|
||||||
// sections of type SHT_PROGBITS and whose name is ..secname are considered ROM segments
|
// sections of type SHT_PROGBITS and whose name is ..secname are considered ROM segments
|
||||||
for (i = 0; i < elf.shnum; i++)
|
for (i = 0; i < elf.shnum; i++)
|
||||||
|
@ -137,38 +150,17 @@ static void parse_input_file(const char *filename)
|
||||||
// so we must ignore the ..secname.bss sections explicitly
|
// so we must ignore the ..secname.bss sections explicitly
|
||||||
&& strchr(sec.name + 2, '.') == NULL)
|
&& strchr(sec.name + 2, '.') == NULL)
|
||||||
{
|
{
|
||||||
|
|
||||||
segment = add_rom_segment(sec.name + 2);
|
segment = add_rom_segment(sec.name + 2);
|
||||||
find_segment_info(&elf, segment);
|
|
||||||
segment->data = elf.data + sec.offset;
|
segment->data = elf.data + sec.offset;
|
||||||
|
segment->romStart = find_rom_address(syms, numRomSymbols, segment->name, "Start");
|
||||||
|
segment->romEnd = find_rom_address(syms, numRomSymbols, segment->name, "End");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// find ROM size
|
g_romSize = find_symbol_value(syms, numRomSymbols, "_RomSize");
|
||||||
for (i = 0; i < elf.numsymbols; i++)
|
|
||||||
{
|
|
||||||
struct Elf32_Symbol sym;
|
|
||||||
|
|
||||||
if (!elf32_get_symbol(&elf, &sym, i))
|
free(syms);
|
||||||
util_fatal_error("invalid or corrupt ELF file");
|
|
||||||
if (strcmp(sym.name, "_RomSize") == 0)
|
|
||||||
{
|
|
||||||
g_romSize = sym.value;
|
|
||||||
goto got_rom_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
util_fatal_error("could not find symbol _RomSize");
|
|
||||||
got_rom_size:
|
|
||||||
|
|
||||||
// verify segment info
|
|
||||||
for (i = 0; i < g_romSegmentsCount; i++)
|
|
||||||
{
|
|
||||||
if (g_romSegments[i].romStart == -1)
|
|
||||||
util_fatal_error("segment %s has no ROM start address defined.", g_romSegments[i].name);
|
|
||||||
if (g_romSegments[i].romEnd == -1)
|
|
||||||
util_fatal_error("segment %s has no ROM end address defined.", g_romSegments[i].name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes the N64 ROM, padding the file size to a multiple of 1 MiB
|
// Writes the N64 ROM, padding the file size to a multiple of 1 MiB
|
||||||
|
@ -188,8 +180,7 @@ static void write_rom_file(const char *filename, int cicType)
|
||||||
}
|
}
|
||||||
|
|
||||||
// pad the remaining space with 0xFF
|
// pad the remaining space with 0xFF
|
||||||
for (i = g_romSize; i < (int) fileSize; i++)
|
memset(buffer + g_romSize, 0xFF, fileSize - g_romSize);
|
||||||
buffer[i] = 0xFF;
|
|
||||||
|
|
||||||
// write checksum
|
// write checksum
|
||||||
if (!n64chksum_calculate(buffer, cicType, chksum))
|
if (!n64chksum_calculate(buffer, cicType, chksum))
|
||||||
|
@ -203,7 +194,7 @@ static void write_rom_file(const char *filename, int cicType)
|
||||||
|
|
||||||
static void usage(const char *execname)
|
static void usage(const char *execname)
|
||||||
{
|
{
|
||||||
printf("usage: %s\n", execname);
|
printf("usage: %s -cic <number> input.elf output.z64\n", execname);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#define _UTIL_H_
|
#define _UTIL_H_
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
__attribute__((format(printf, 1, 2)))
|
__attribute__((format(printf, 1, 2), noreturn))
|
||||||
#endif
|
#endif
|
||||||
void util_fatal_error(const char *msgfmt, ...);
|
void util_fatal_error(const char *msgfmt, ...);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue