Fix update, remove _RomPos from linker script

This commit is contained in:
Tharo 2025-09-02 23:36:43 +01:00
parent a1ef3d254c
commit acf082aef0
5 changed files with 84 additions and 56 deletions

View File

@ -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)

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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);
}