gbdk-2020 | GameBoy Development Kit |
| download: https://git.y1.nz/archives/gbdk.tar.gz | |
| README | Files | Log | Refs | LICENSE |
commit f1c6e8206742b091ab059bd60557a3f895a5ad3c parent 64eb14fb979411f2346717dfd2c574705a8e8cb2 Author: Toxa <56631470+untoxa@users.noreply.github.com> Date: Thu, 19 Jun 2025 11:17:16 +0300 Merge pull request #790 from bbbbbr/bankpack/linkerfile_output_order Bankpack: Linkerfile output order matches internal packing order Diffstat:
| M | gbdk-support/bankpack/common.h | 4 | ++++ |
| M | gbdk-support/bankpack/files.c | 49 | +++++++++++++++++++++++++++++++++++++++++++++++-- |
| M | gbdk-support/bankpack/files.h | 7 | +++++++ |
| M | gbdk-support/bankpack/obj_data.c | 17 | +++++++++++------ |
4 files changed, 69 insertions(+), 8 deletions(-)
diff --git a/gbdk-support/bankpack/common.h b/gbdk-support/bankpack/common.h @@ -2,6 +2,10 @@ #ifndef _COMMON_H #define _COMMON_H +#define QSORT_A_FIRST -1 +#define QSORT_A_SAME 0 +#define QSORT_A_AFTER 1 + enum { MBC_TYPE_NONE = 0, MBC_TYPE_MBC1 = 1, diff --git a/gbdk-support/bankpack/files.c b/gbdk-support/bankpack/files.c @@ -85,6 +85,40 @@ void files_set_linkerfile_outname(char * filename) { } +// qsort compare rule function for linkerfile_order +static int linkerfile_order_compare(const void* a, const void* b) { + + // Sort by linkerfile_order [asc] + if (((file_order_t *)a)->linkerfile_order != ((file_order_t *)b)->linkerfile_order) + return (((file_order_t *)a)->linkerfile_order < ((file_order_t *)b)->linkerfile_order) ? QSORT_A_FIRST : QSORT_A_AFTER; + else + return QSORT_A_SAME; +} + +// Set linkerfile order +// +// Helps ensure fixed bank areas (hopefully) get linked/placed before autobank. +// Intended to facilitate alignment assumptions for size padded object files. +// - Files that only have non-banked data ("_CODE", "_HOME") will always be first in the order +// - See area_item_compare() for full details of how linkerfile_order gets set +static void linkerfile_output_order_sort(const file_item * p_files, file_order_t * p_filelist_order, const uint32_t count) { + + if (p_filelist_order && p_files) { + // Create sort-able list from list of files and their assigned linkerfile order + for (uint8_t c = 0; c < filelist.count; c++) { + p_filelist_order[c].file_id = c; + p_filelist_order[c].linkerfile_order = p_files[c].linkerfile_order; + } + + // Sort the new list by linkerfile order + qsort (p_filelist_order, count, sizeof(file_order_t), linkerfile_order_compare); + } else { + printf("BankPack: ERROR: failed to allocate memory for sorting linkerfile output\n"); + exit(EXIT_FAILURE); + } +} + + // Writes a list of loaded object filenames to // a linkerfile (one filename per line) void files_write_linkerfile(void) { @@ -92,13 +126,20 @@ void files_write_linkerfile(void) { file_item * files = (file_item *)filelist.p_array; FILE * out_file; + // Instead of sorting the file array itself, which would break references + // (i.e. "files[ areas[c].file_id ]."), create a sorted reference array to order the file output + file_order_t * filelist_order = malloc(filelist.count * sizeof(file_order_t)); + linkerfile_output_order_sort(files, filelist_order, filelist.count); + // Open the linkerfile output and write all object filenames out_file = fopen(g_out_linkerfile_name, "w"); if (out_file) { // Process stored file names - for (c = 0; c < filelist.count; c++) - fprintf(out_file, "%s\n", files[c].name_out); + for (c = 0; c < filelist.count; c++) { + // printf("linkerfile out: c = %d : file_id = %d linkerfile_order = %d, name = %s\n", c, filelist_order[c].file_id, filelist_order[c].linkerfile_order, files[ filelist_order[c].file_id ].name_out); + fprintf(out_file, "%s\n", files[ filelist_order[c].file_id ].name_out); + } fclose(out_file); @@ -107,6 +148,9 @@ void files_write_linkerfile(void) { printf("BankPack: ERROR: failed to open output linkerfile: %s\n", g_out_linkerfile_name); exit(EXIT_FAILURE); } + + if (filelist_order) + free(filelist_order); } @@ -120,6 +164,7 @@ void files_add(char * filename) { newfile.name_out[0] = '\0'; newfile.rewrite_needed = false; newfile.bank_num = BANK_NUM_UNASSIGNED; + newfile.linkerfile_order = LINKERFILE_ORDER_FIRST; // This won't get changed for non-banked object files list_additem(&filelist, &newfile); } diff --git a/gbdk-support/bankpack/files.h b/gbdk-support/bankpack/files.h @@ -13,8 +13,15 @@ typedef struct file_item { bool rewrite_needed; char name_out[MAX_FILE_STR]; unsigned int obj_file_format; + uint32_t linkerfile_order; } file_item; +typedef struct file_order_t { + uint32_t file_id; + uint32_t linkerfile_order; +} file_order_t; + +#define LINKERFILE_ORDER_FIRST 0 void files_init(void); void files_cleanup(void); diff --git a/gbdk-support/bankpack/obj_data.c b/gbdk-support/bankpack/obj_data.c @@ -370,14 +370,14 @@ static void banks_assign_area(area_item * p_area) { } -#define QSORT_A_FIRST -1 -#define QSORT_A_SAME 0 -#define QSORT_A_AFTER 1 - // qsort compare rule function for sorting areas static int area_item_compare(const void* a, const void* b) { - // sort by bank [asc] (fixed vs auto-bank), then by size [desc] + // Sort: + // - First by bank num [asc] (implied fixed first, since fixed [0..254] < auto [255]) + // - Then by size [desc] + // + // This assumes the autobank indicator (255) is larger than all fixed bank numbers (< 255) if (((area_item *)a)->bank_num_in != ((area_item *)b)->bank_num_in) return (((area_item *)a)->bank_num_in < ((area_item *)b)->bank_num_in) ? QSORT_A_FIRST : QSORT_A_AFTER; else if (((area_item *)a)->size != ((area_item *)b)->size) @@ -401,13 +401,18 @@ void obj_data_process(list_type * p_filelist) { symbol_item * symbols = (symbol_item *)symbollist.p_array; file_item * files = (file_item *)(p_filelist->p_array); + // Sort all areas (see function for sort order) areas_sort(); // Assign areas to banks for (c = 0; c < arealist.count; c++) { banks_assign_area(&(areas[c])); + // Set linkerfile order based on sort order above + // The + 1 is to separate banked from non-banked files so non-banked always go first + // (non-banked files aren't passed into this function, so stay at default [0]) + files[ areas[c].file_id ].linkerfile_order = c + 1; - // If areas was auto-banked then set bank number in associated file + // If area was auto-banked then set bank number in associated file if ((areas[c].bank_num_in == BANK_NUM_AUTO) && (areas[c].bank_num_out != BANK_NUM_UNASSIGNED)) {
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.