diff --git a/Makefile b/Makefile index b50811b0ee..122f56b4e9 100644 --- a/Makefile +++ b/Makefile @@ -847,7 +847,7 @@ $(ROMC): $(ROM) $(ELF) $(BUILD_DIR)/compress_ranges.txt COM_PLUGIN := tools/com-plugin/common-plugin.so -LDFLAGS := -T $(LDSCRIPT) -T $(BUILD_DIR)/linker_scripts/makerom.ld -T $(BUILD_DIR)/undefined_syms.txt --no-check-sections --accept-unknown-input-arch --emit-relocs -Map $(MAP) +LDFLAGS := -T $(LDSCRIPT) -T $(BUILD_DIR)/linker_scripts/makerom.ld -T $(BUILD_DIR)/undefined_syms.txt --emit-relocs -Map $(MAP) ifeq ($(PLATFORM),IQUE) ifeq ($(NON_MATCHING),0) LDFLAGS += -plugin $(COM_PLUGIN) -plugin-opt order=$(BASEROM_DIR)/bss-order.txt @@ -857,6 +857,7 @@ endif $(ELF): $(TEXTURE_FILES_OUT) $(ASSET_FILES_OUT) $(O_FILES) $(SEGMENT_FILES) $(OVL_RELOC_FILES) $(LDSCRIPT) \ $(BUILD_DIR)/linker_scripts/makerom.ld $(BUILD_DIR)/undefined_syms.txt \ + $(BUILD_DIR)/src/makerom/rom_header.o $(BUILD_DIR)/src/makerom/ipl3.o $(BUILD_DIR)/src/makerom/entry.o \ $(SAMPLEBANK_O_FILES) $(SOUNDFONT_O_FILES) $(SEQUENCE_O_FILES) \ $(BUILD_DIR)/assets/audio/sequence_font_table.o $(BUILD_DIR)/assets/audio/audiobank_padding.o $(LD) $(LDFLAGS) -o $@ @@ -876,12 +877,12 @@ $(O_FILES): | asset_files $(BUILD_DIR)/spec: $(SPEC) $(SPEC_INCLUDES) $(CPP) $(CPPFLAGS) -MD -MP -MF $@.d -MT $@ -I. $< | $(BUILD_DIR_REPLACE) > $@ -$(LDSCRIPT): $(BUILD_DIR)/$(SPEC) - $(MKLDSCRIPT) $< $@ $(SEGMENTS_DIR) +$(LDSCRIPT): $(BUILD_DIR)/spec + $(MKLDSCRIPT) $< $@ $(BUILD_DIR)/src/makerom $(SEGMENTS_DIR) # Generates a makefile containing rules for building .plf files # from overlay .o files for every overlay defined in the spec. -$(SEGMENTS_DIR)/Makefile: $(BUILD_DIR)/$(SPEC) +$(SEGMENTS_DIR)/Makefile: $(BUILD_DIR)/spec $(MKSPECRULES) $< $(SEGMENTS_DIR) $@ # Generates relocations for each overlay after partial linking so that the final @@ -950,7 +951,7 @@ endif $(OBJDUMP_CMD) $(BUILD_DIR)/src/makerom/ipl3.o: $(EXTRACTED_DIR)/incbin/ipl3 - $(OBJCOPY) -I binary -O elf32-big --rename-section .data=.text $< $@ + $(OBJCOPY) -I binary -O $(LD_OFORMAT) --rename-section .data=.text $< $@ $(BUILD_DIR)/src/%.o: src/%.s ifeq ($(COMPILER),ido) diff --git a/spec/spec b/spec/spec index e1103bb084..10df3ddc42 100644 --- a/spec/spec +++ b/spec/spec @@ -4,16 +4,6 @@ #include "include/versions.h" -beginseg - name "makerom" - // We set the address of the makerom segment as 0x80000400 - 0x1000, since the ROM header and IPL3 together - // are 0x1000 bytes long and we want the entry code to end up at address 0x80000400. - address 0x7FFFF400 - include "$(BUILD_DIR)/src/makerom/rom_header.o" - include "$(BUILD_DIR)/src/makerom/ipl3.o" - include "$(BUILD_DIR)/src/makerom/entry.o" -endseg - beginseg name "boot" @@ -674,7 +664,7 @@ beginseg // audio #if OOT_VERSION < NTSC_1_1 || !PLATFORM_N64 - pad_text + include "$(BUILD_DIR)/__pad_text.o" #endif include "$(BUILD_DIR)/src/audio/internal/data.o" include "$(BUILD_DIR)/src/audio/internal/synthesis.o" @@ -683,16 +673,16 @@ beginseg include "$(BUILD_DIR)/src/audio/internal/thread.o" include "$(BUILD_DIR)/src/audio/internal/os.o" #if OOT_PAL_N64 - pad_text - pad_text - pad_text + include "$(BUILD_DIR)/__pad_text.o" + include "$(BUILD_DIR)/__pad_text.o" + include "$(BUILD_DIR)/__pad_text.o" #endif include "$(BUILD_DIR)/src/audio/internal/playback.o" include "$(BUILD_DIR)/src/audio/internal/effects.o" include "$(BUILD_DIR)/src/audio/internal/seqplayer.o" include "$(BUILD_DIR)/src/audio/game/general.o" #if !PLATFORM_N64 && !DEBUG_FEATURES - pad_text + include "$(BUILD_DIR)/__pad_text.o" #endif include "$(BUILD_DIR)/src/audio/game/sfx_params.o" include "$(BUILD_DIR)/src/audio/game/sfx.o" @@ -742,7 +732,9 @@ beginseg include "$(BUILD_DIR)/src/libc64/malloc.o" include "$(BUILD_DIR)/src/libc64/qrand.o" include "$(BUILD_DIR)/src/libc64/__osMalloc_n64.o" +#if !DEBUG_FEATURES include "$(BUILD_DIR)/src/libc64/sprintf.o" +#endif include "$(BUILD_DIR)/src/libc64/aprintf.o" #elif PLATFORM_GC include "$(BUILD_DIR)/src/libc64/math64.o" @@ -750,7 +742,9 @@ beginseg include "$(BUILD_DIR)/src/libc64/malloc.o" include "$(BUILD_DIR)/src/libc64/qrand.o" include "$(BUILD_DIR)/src/libc64/__osMalloc_gc.o" +#if !DEBUG_FEATURES include "$(BUILD_DIR)/src/libc64/sprintf.o" +#endif include "$(BUILD_DIR)/src/libc64/aprintf.o" include "$(BUILD_DIR)/src/libc64/sleep.o" #elif PLATFORM_IQUE @@ -761,7 +755,9 @@ beginseg include "$(BUILD_DIR)/src/libc64/fp.o" include "$(BUILD_DIR)/src/libc64/qrand.o" include "$(BUILD_DIR)/src/libc64/sleep.o" +#if !DEBUG_FEATURES include "$(BUILD_DIR)/src/libc64/sprintf.o" +#endif #endif // jpeg diff --git a/tools/mkdmadata.c b/tools/mkdmadata.c index fbbd5da9e6..c9a3235886 100644 --- a/tools/mkdmadata.c +++ b/tools/mkdmadata.c @@ -14,9 +14,9 @@ int g_segmentsCount; static void write_dmadata_table(FILE *fout) { - int i; + fprintf(fout, "DEFINE_DMA_ENTRY(makerom, \"makerom\")\n"); - for (i = 0; i < g_segmentsCount; i++) { + for (int i = 0; i < g_segmentsCount; i++) { // Don't emit dma entry for segments set with NOLOAD if (g_segments[i].flags & FLAG_NOLOAD) { continue; diff --git a/tools/mkldscript.c b/tools/mkldscript.c index efba2c94ec..ee5efc082b 100644 --- a/tools/mkldscript.c +++ b/tools/mkldscript.c @@ -19,31 +19,58 @@ static void write_includes(const struct Segment *seg, FILE *fout, const char *se fprintf(fout, " %s/%s.plf (%s*)\n", segments_dir, seg->name, section); } -static void write_ld_script(FILE *fout, const char *segments_dir) +static void write_ld_script(FILE *fout, uint32_t entrypoint_addr, const char *makerom_dir, const char *segments_dir) { int i; fputs("OUTPUT_ARCH (mips)\n" "\n" "SECTIONS\n" - "{\n" - " _RomPos = 0;\n" - "\n", + "{\n", fout); + fprintf(fout, + " /* makerom */" "\n" + "" "\n" + " ..makerom.hdr 0 : AT(0)" "\n" + " {" "\n" + " %s/rom_header.o(.text*)" "\n" + " %s/rom_header.o(.data*)" "\n" + " %s/rom_header.o(.rodata*)" "\n" + " }" "\n" + " ..makerom.ipl 0 : AT(SIZEOF(..makerom.hdr))" "\n" + " {" "\n" + " %s/ipl3.o(.text*)" "\n" + " %s/ipl3.o(.data*)" "\n" + " %s/ipl3.o(.rodata*)" "\n" + " }" "\n" + " ..makerom.ent 0x%08X : AT(SIZEOF(..makerom.hdr) + SIZEOF(..makerom.ipl))" "\n" + " {" "\n" + " %s/entry.o(.text*)" "\n" + " %s/entry.o(.data*)" "\n" + " %s/entry.o(.rodata*)" "\n" + " }" "\n" + " _makeromSegmentRomStart = LOADADDR(..makerom.hdr);" "\n" + " _makeromSegmentRomEnd = LOADADDR(..makerom.ent) + SIZEOF(..makerom.ent);" "\n" + " _makeromSegmentRomSize = SIZEOF(..makerom.hdr) + SIZEOF(..makerom.ipl) + SIZEOF(..makerom.ent);" "\n" + "" "\n", + makerom_dir, makerom_dir, makerom_dir, + makerom_dir, makerom_dir, makerom_dir, + entrypoint_addr, + makerom_dir, makerom_dir, makerom_dir + ); + + const char *last_end = "makerom"; + uint32_t last_romalign = 0; + for (i = 0; i < g_segmentsCount; i++) { const struct Segment *seg = &g_segments[i]; fprintf(fout, " /* %s */\n\n", seg->name); - // align start of ROM segment - if (seg->fields & (1 << STMT_romalign)) - fprintf(fout, " _RomPos = ALIGN(_RomPos, %i);\n", seg->romalign); - // Begin initialized data (.text, .data, .rodata) - fprintf(fout, " _%sSegmentRomStartTemp = _RomPos;\n" - " _%sSegmentRomStart = _%sSegmentRomStartTemp;\n" - " ..%s ", seg->name, seg->name, seg->name, seg->name); + + fprintf(fout, " ..%s ", seg->name); if (seg->fields & (1 << STMT_after)) // Continue after the requested segment, aligning to the required alignment for the new segment. @@ -58,16 +85,20 @@ static void write_ld_script(FILE *fout, const char *segments_dir) // Continue after previous segment, aligning to the required alignment for the new segment. fprintf(fout, "ALIGN(0x%X)", seg->align); - // AT(_RomPos) isn't necessary, but adds useful "load address" lines to the map file. + // AT(...) isn't necessary, but adds useful "load address" lines to the map file. // Also force an alignment of at least 0x10 at the start of any segment. This is especially important for // overlays as the final link step must not introduce alignment padding between the SegmentTextStart symbol // and the section contents as this would cause all generated relocations done prior to be wrong. - fprintf(fout, " : AT(_RomPos)\n" - " {\n" + uint32_t next_romalign = (seg->fields & (1 << STMT_romalign)) ? seg->romalign : 0x10; + fprintf(fout, " : AT(ALIGN(_%sSegmentRomEnd, %u))\n", last_end, + (last_romalign > next_romalign) ? last_romalign : next_romalign); + last_romalign = next_romalign; + + fprintf(fout, " {\n" " . = ALIGN(0x10);\n" " _%sSegmentStart = .;\n" "\n", - seg->name); + seg->name); // Write .text fprintf(fout, " _%sSegmentTextStart = .;\n", seg->name); @@ -106,31 +137,25 @@ static void write_ld_script(FILE *fout, const char *segments_dir) "\n", seg->name, segments_dir, seg->name, seg->name, seg->name, seg->name, seg->name); } - const char *last_loadable = (seg->flags & FLAG_OVL) ? "Ovl" : "RoData"; - // End initialized data. fprintf(fout, " }\n" - " _RomPos += ( _%sSegment%sEnd - _%sSegmentTextStart );\n" - " _%sSegmentRomEndTemp = _RomPos;\n" - " _%sSegmentRomEnd = _%sSegmentRomEndTemp;\n" - " _%sSegmentRomSize = ABSOLUTE( _%sSegmentRomEnd - _%sSegmentRomStart );\n" + " _%sSegmentRomStart = LOADADDR(..%s);\n" + " _%sSegmentRomEnd = LOADADDR(..%s) + SIZEOF(..%s);\n" + " _%sSegmentRomSize = SIZEOF(..%s);\n" "\n", - seg->name, last_loadable, seg->name, seg->name, seg->name, seg->name, - seg->name, seg->name, seg->name); - - // Align end of ROM segment - if (seg->fields & (1 << STMT_romalign)) - fprintf(fout, " _RomPos = ALIGN(_RomPos, %i);\n", seg->romalign); + seg->name, seg->name, + seg->name, seg->name, seg->name, + seg->name, seg->name); // Begin uninitialized data (.bss, COMMON) // Note we must enforce a minimum alignment of at least 8 for // bss sections due to how bss is cleared in steps of 8 in // entry.s, and more widely it's more efficient. - fprintf(fout, " ..%s.bss (NOLOAD) :\n" + fprintf(fout, " ..%s.bss (NOLOAD) : AT(_%sSegmentRomEnd)\n" " {\n" " . = ALIGN(8);\n" " _%sSegmentBssStart = .;\n", - seg->name, seg->name); + seg->name, seg->name, seg->name); // Write .bss and COMMON write_includes(seg, fout, segments_dir, ".bss"); @@ -145,9 +170,11 @@ static void write_ld_script(FILE *fout, const char *segments_dir) " }\n" "\n", seg->name, seg->name, seg->name, seg->name, seg->name); + + last_end = seg->name; } - fputs(" _RomSize = _RomPos;\n\n", fout); + fprintf(fout, " _RomSize = ALIGN(_%sSegmentRomEnd, %u);\n\n", last_end, last_romalign); // Debugging sections fputs( @@ -222,9 +249,10 @@ static void write_ld_script(FILE *fout, const char *segments_dir) static void usage(const char *execname) { fprintf(stderr, "Nintendo 64 linker script generation tool v0.04\n" - "usage: %s SPEC_FILE LD_SCRIPT SEGMENTS_DIR\n" + "usage: %s SPEC_FILE LD_SCRIPT SEGMENTS_DIR MAKEROM_DIR\n" "SPEC_FILE file describing the organization of object files into segments\n" "LD_SCRIPT filename of output linker script\n" + "MAKEROM_DIR dir name containing makerom build objects\n" "SEGMENTS_DIR dir name containing partially linked overlay segments\n", execname); } @@ -235,7 +263,7 @@ int main(int argc, char **argv) void *spec; size_t size; - if (argc != 4) { + if (argc != 5) { usage(argv[0]); return EXIT_FAILURE; } @@ -246,7 +274,9 @@ int main(int argc, char **argv) ldout = fopen(argv[2], "w"); if (ldout == NULL) util_fatal_error("failed to open file '%s' for writing", argv[2]); - write_ld_script(ldout, argv[3]); + + uint32_t entrypoint_addr = 0x80000400; + write_ld_script(ldout, entrypoint_addr, argv[3], argv[4]); fclose(ldout); free_rom_spec(g_segments, g_segmentsCount); diff --git a/tools/mkspecrules.c b/tools/mkspecrules.c index 1238a94128..6a6866a919 100644 --- a/tools/mkspecrules.c +++ b/tools/mkspecrules.c @@ -19,9 +19,10 @@ static void write_overlay_rules(FILE *fout, const char *ovls_dir) fprintf(fout, "%s/%s.plf:", ovls_dir, seg->name); for (j = 0; j < seg->includesCount; j++) fprintf(fout, " \\\n\t\t%s", seg->includes[j].fpath); + fprintf(fout, " \\\n\t\t$(SEGMENTS_DIR)/Makefile"); fprintf(fout, "\n" "\t@echo Linking \"%s\"\n" - "\t$(SEG_VERBOSE)$(LD) $(SEG_LDFLAGS) $^ -o $@\n" + "\t$(SEG_VERBOSE)$(LD) $(SEG_LDFLAGS) $(filter %%.o, $^) -o $@\n" "\n", seg->name); }