summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzelda2774 <69368340+zelda2774@users.noreply.github.com>2020-08-23 19:43:26 +0200
committerGitHub <noreply@github.com>2020-08-23 13:43:26 -0400
commit281aaa0cb6a55f19eceb322871a8d27da9e0e8b2 (patch)
tree0d3415404941807b40c89ba66032986621f89982
parentdea5f4aae528e9af6ad597d3075403a8d226ac61 (diff)
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>
-rw-r--r--Makefile5
-rw-r--r--tools/elf2rom.c121
-rw-r--r--tools/util.h2
3 files changed, 59 insertions, 69 deletions
diff --git a/Makefile b/Makefile
index 75cc65cfa..592f7f862 100644
--- a/Makefile
+++ b/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'
@@ -109,8 +109,7 @@ O_FILES := $(foreach f,$(S_FILES:.s=.o),build/$f) \
# $(foreach f,$(TEXTURE_FILES_CI8:.ci8.png=.ci8),build/$f) \
# create build directories
-$(shell mkdir -p build/baserom)
-$(foreach dir,$(SRC_DIRS) $(ASM_DIRS) $(TEXTURE_DIRS) $(TEXTURE_BIN_DIRS) $(SCENE_DIRS),$(shell mkdir -p build/$(dir)))
+$(shell mkdir -p build/baserom $(foreach dir,$(SRC_DIRS) $(ASM_DIRS) $(TEXTURE_DIRS) $(TEXTURE_BIN_DIRS) $(SCENE_DIRS),build/$(dir)))
build/src/libultra_boot_O1/%.o: OPTFLAGS := -O1
build/src/libultra_boot_O2/%.o: OPTFLAGS := -O2
diff --git a/tools/elf2rom.c b/tools/elf2rom.c
index 8f4441293..366c05f08 100644
--- a/tools/elf2rom.c
+++ b/tools/elf2rom.c
@@ -64,58 +64,58 @@ static struct RomSegment *add_rom_segment(const char *name)
g_romSegmentsCount++;
g_romSegments = realloc(g_romSegments, g_romSegmentsCount * sizeof(*g_romSegments));
-
g_romSegments[index].name = name;
- g_romSegments[index].romStart = -1;
- g_romSegments[index].romEnd = -1;
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;
- char *romStartSymName = sprintf_alloc("_%sSegmentRomStart", segment->name);
- char *romEndSymName = sprintf_alloc("_%sSegmentRomEnd", segment->name);
+ struct Elf32_Symbol *sym;
+ int lo, hi, mid, cmp;
+
+ // Binary search for the symbol. We maintain the invariant that [lo, hi) is
+ // the interval that remains to search.
+ lo = 0;
+ hi = numsymbols;
+ while (lo < hi)
+ {
+ mid = lo + (hi - lo) / 2;
+ sym = &syms[mid];
+ cmp = strcmp(sym->name, name);
+
+ if (cmp == 0)
+ return (int) sym->value;
+ else if (cmp < 0)
+ lo = mid + 1;
+ else
+ hi = mid;
+ }
- segment->romStart = -1;
- segment->romEnd = -1;
+ util_fatal_error("Symbol %s is not defined\n", name);
+}
- // TODO: use a hashmap for this instead of an O(n) loop
- for (i = 0; i < elf->numsymbols; i++)
- {
- struct Elf32_Symbol sym;
-
- if (!elf32_get_symbol(elf, &sym, i))
- util_fatal_error("invalid or corrupt ELF file");
+static int find_rom_address(struct Elf32_Symbol *syms, int numsymbols, const char *name, const char *suffix)
+{
+ char *symName = sprintf_alloc("_%sSegmentRom%s", name, suffix);
+ int ret = find_symbol_value(syms, numsymbols, symName);
+ free(symName);
+ return ret;
+}
- if (strcmp(sym.name, romStartSymName) == 0)
- {
- segment->romStart = sym.value;
- 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("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);
- free(romEndSymName);
+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)
{
struct Elf32 elf;
+ struct Elf32_Symbol *syms;
const void *data;
size_t size;
+ int numRomSymbols;
int i;
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)
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
// sections of type SHT_PROGBITS and whose name is ..secname are considered ROM segments
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
&& strchr(sec.name + 2, '.') == NULL)
{
-
segment = add_rom_segment(sec.name + 2);
- find_segment_info(&elf, segment);
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
- for (i = 0; i < elf.numsymbols; i++)
- {
- struct Elf32_Symbol sym;
+ g_romSize = find_symbol_value(syms, numRomSymbols, "_RomSize");
- if (!elf32_get_symbol(&elf, &sym, i))
- 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);
- }
+ free(syms);
}
// 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
- for (i = g_romSize; i < (int) fileSize; i++)
- buffer[i] = 0xFF;
+ memset(buffer + g_romSize, 0xFF, fileSize - g_romSize);
// write checksum
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)
{
- printf("usage: %s\n", execname);
+ printf("usage: %s -cic <number> input.elf output.z64\n", execname);
}
int main(int argc, char **argv)
diff --git a/tools/util.h b/tools/util.h
index 8659e6f35..e34800a19 100644
--- a/tools/util.h
+++ b/tools/util.h
@@ -2,7 +2,7 @@
#define _UTIL_H_
#ifdef __GNUC__
-__attribute__((format(printf, 1, 2)))
+__attribute__((format(printf, 1, 2), noreturn))
#endif
void util_fatal_error(const char *msgfmt, ...);