mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
Rewrite RGBLINK entirely
The goal was to improve readability, but along the way a few things were gained. - Sorted sym and map files - Infrastructure for supporting multiple .o versions - Valgrind-proof, as far as my testing goes anyways - Improved verbosity messages - Added error checking - Performance improvements, see end of commit message The readability improvement was spurred while trying to make sense of the old code while trying to implement features such as sorted sym and map files. I also did my best to remove hardcoded logic, such that modifications should be doable; for example, "RAM loading" sections, which are linked against a different location than the one they're stored at. Some work remains to be done, see the "TODO:" and "FIXME:" comments. Further, while regression tests pass, this new linker should be tested on different codebases (ideally while instrumented with `make develop` and under valgrind). The few errors spotted in the man pages (alignment) need to be corrected. Finally, documentation comments need to be written, I have written a lot of them but not all. This also provides a significant performance boost (benchmarked with a 51994-symbol project): Current master RGBLINK: 2.02user 0.03system 0:02.06elapsed 99%CPU (0avgtext+0avgdata 84336maxresident)k 0inputs+11584outputs (0major+20729minor)pagefaults 0swaps Rewritten RGBLINK: 0.19user 0.06system 0:00.63elapsed 40%CPU (0avgtext+0avgdata 32460maxresident)k 23784inputs+11576outputs (0major+7672minor)pagefaults 0swaps
This commit is contained in:
@@ -1,54 +1,29 @@
|
||||
/*
|
||||
* This file is part of RGBDS.
|
||||
*
|
||||
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
|
||||
* Copyright (c) 1997-2019, Carsten Sorensen and RGBDS contributors.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/* Assigning all sections a place */
|
||||
#ifndef RGBDS_LINK_ASSIGN_H
|
||||
#define RGBDS_LINK_ASSIGN_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "mylink.h"
|
||||
|
||||
/* Bank numbers as seen by the linker */
|
||||
enum eBankDefine {
|
||||
BANK_INDEX_ROM0 = 0,
|
||||
BANK_INDEX_ROMX = BANK_INDEX_ROM0 + BANK_COUNT_ROM0,
|
||||
BANK_INDEX_WRAM0 = BANK_INDEX_ROMX + BANK_COUNT_ROMX,
|
||||
BANK_INDEX_WRAMX = BANK_INDEX_WRAM0 + BANK_COUNT_WRAM0,
|
||||
BANK_INDEX_VRAM = BANK_INDEX_WRAMX + BANK_COUNT_WRAMX,
|
||||
BANK_INDEX_OAM = BANK_INDEX_VRAM + BANK_COUNT_VRAM,
|
||||
BANK_INDEX_HRAM = BANK_INDEX_OAM + BANK_COUNT_OAM,
|
||||
BANK_INDEX_SRAM = BANK_INDEX_HRAM + BANK_COUNT_HRAM,
|
||||
BANK_INDEX_MAX = BANK_INDEX_SRAM + BANK_COUNT_SRAM
|
||||
};
|
||||
extern uint64_t nbSectionsToAssign;
|
||||
|
||||
extern int32_t MaxBankUsed;
|
||||
extern int32_t MaxAvail[BANK_INDEX_MAX];
|
||||
/**
|
||||
* Assigns all sections a slice of the address space
|
||||
*/
|
||||
void assign_AssignSections(void);
|
||||
|
||||
int32_t area_Avail(int32_t bank);
|
||||
void AssignSections(void);
|
||||
void CreateSymbolTable(void);
|
||||
struct sSection *GetSectionByName(const char *name);
|
||||
int32_t IsSectionNameInUse(const char *name);
|
||||
void SetLinkerscriptName(char *tzLinkerscriptFile);
|
||||
int32_t IsSectionSameTypeBankAndAttrs(const char *name,
|
||||
enum eSectionType type, int32_t bank,
|
||||
int32_t org, int32_t align);
|
||||
uint32_t AssignSectionAddressAndBankByName(const char *name, uint32_t address,
|
||||
int32_t bank);
|
||||
|
||||
int BankIndexIsROM0(int32_t bank);
|
||||
int BankIndexIsROMX(int32_t bank);
|
||||
int BankIndexIsWRAM0(int32_t bank);
|
||||
int BankIndexIsWRAMX(int32_t bank);
|
||||
int BankIndexIsVRAM(int32_t bank);
|
||||
int BankIndexIsOAM(int32_t bank);
|
||||
int BankIndexIsHRAM(int32_t bank);
|
||||
int BankIndexIsSRAM(int32_t bank);
|
||||
/**
|
||||
* `free`s all assignment memory that was allocated.
|
||||
*/
|
||||
void assign_Cleanup(void);
|
||||
|
||||
#endif /* RGBDS_LINK_ASSIGN_H */
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
/*
|
||||
* This file is part of RGBDS.
|
||||
*
|
||||
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef RGBDS_LINK_LIBRARY_H
|
||||
#define RGBDS_LINK_LIBRARY_H
|
||||
|
||||
void AddNeededModules(void);
|
||||
|
||||
#endif /* RGBDS_LINK_LIBRARY_H */
|
||||
@@ -1,17 +1,35 @@
|
||||
/*
|
||||
* This file is part of RGBDS.
|
||||
*
|
||||
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
|
||||
* Copyright (c) 1997-2019, Carsten Sorensen and RGBDS contributors.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/* Declarations that all modules use, as well as `main` and related */
|
||||
#ifndef RGBDS_LINK_MAIN_H
|
||||
#define RGBDS_LINK_MAIN_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
extern int32_t fillchar;
|
||||
extern char *smartlinkstartsymbol;
|
||||
/* Variables related to CLI options */
|
||||
extern bool isDmgMode;
|
||||
extern FILE *linkerScript;
|
||||
extern FILE *mapFile;
|
||||
extern FILE *symFile;
|
||||
extern FILE *overlayFile;
|
||||
extern FILE *outputFile;
|
||||
extern uint8_t padValue;
|
||||
extern bool is32kMode;
|
||||
extern bool beVerbose;
|
||||
extern bool isWRA0Mode;
|
||||
|
||||
/* Helper macro for printing verbose-mode messages */
|
||||
#define verbosePrint(...) do { \
|
||||
if (beVerbose) \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#endif /* RGBDS_LINK_MAIN_H */
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
* This file is part of RGBDS.
|
||||
*
|
||||
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef RGBDS_LINK_MAPFILE_H
|
||||
#define RGBDS_LINK_MAPFILE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void SetMapfileName(char *name);
|
||||
void SetSymfileName(char *name);
|
||||
void CloseMapfile(void);
|
||||
void MapfileWriteSection(const struct sSection *pSect);
|
||||
void MapfileInitBank(int32_t bank);
|
||||
void MapfileCloseBank(int32_t slack);
|
||||
|
||||
#endif /* RGBDS_LINK_MAPFILE_H */
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* This file is part of RGBDS.
|
||||
*
|
||||
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef RGBDS_LINK_LINK_H
|
||||
#define RGBDS_LINK_LINK_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "linkdefs.h"
|
||||
|
||||
extern int32_t options;
|
||||
|
||||
#define OPT_TINY 0x01
|
||||
#define OPT_SMART_C_LINK 0x02
|
||||
#define OPT_OVERLAY 0x04
|
||||
#define OPT_CONTWRAM 0x08
|
||||
#define OPT_DMG_MODE 0x10
|
||||
|
||||
struct sSection {
|
||||
int32_t nBank;
|
||||
int32_t nOrg;
|
||||
int32_t nAlign;
|
||||
uint8_t oAssigned;
|
||||
|
||||
char *pzName;
|
||||
int32_t nByteSize;
|
||||
enum eSectionType Type;
|
||||
uint8_t *pData;
|
||||
int32_t nNumberOfSymbols;
|
||||
struct sSymbol **tSymbols;
|
||||
struct sPatch *pPatches;
|
||||
struct sSection *pNext;
|
||||
};
|
||||
|
||||
struct sSymbol {
|
||||
char *pzName;
|
||||
enum eSymbolType Type;
|
||||
|
||||
/* The following 3 items only valid when Type!=SYM_IMPORT */
|
||||
int32_t nSectionID; /* Internal to object.c */
|
||||
struct sSection *pSection;
|
||||
int32_t nOffset;
|
||||
|
||||
char *pzObjFileName; /* Object file where the symbol is located. */
|
||||
char *pzFileName; /* Source file where the symbol was defined. */
|
||||
uint32_t nFileLine; /* Line where the symbol was defined. */
|
||||
};
|
||||
|
||||
struct sPatch {
|
||||
char *pzFilename;
|
||||
int32_t nLineNo;
|
||||
int32_t nOffset;
|
||||
enum ePatchType Type;
|
||||
int32_t nRPNSize;
|
||||
uint8_t *pRPN;
|
||||
struct sPatch *pNext;
|
||||
uint8_t oRelocPatch;
|
||||
};
|
||||
|
||||
extern struct sSection *pSections;
|
||||
extern struct sSection *pLibSections;
|
||||
|
||||
#endif /* RGBDS_LINK_LINK_H */
|
||||
@@ -1,14 +1,30 @@
|
||||
/*
|
||||
* This file is part of RGBDS.
|
||||
*
|
||||
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
|
||||
* Copyright (c) 1997-2019, Carsten Sorensen and RGBDS contributors.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/* Declarations related to processing of object (.o) files */
|
||||
|
||||
#ifndef RGBDS_LINK_OBJECT_H
|
||||
#define RGBDS_LINK_OBJECT_H
|
||||
|
||||
void obj_Readfile(char *tzObjectfile);
|
||||
/**
|
||||
* Read an object (.o) file, and add its info to the data structures.
|
||||
* @param fileName A path to the object file to be read
|
||||
*/
|
||||
void obj_ReadFile(char const *fileName);
|
||||
|
||||
/**
|
||||
* Perform validation on the object files' contents
|
||||
*/
|
||||
void obj_DoSanityChecks(void);
|
||||
|
||||
/**
|
||||
* `free`s all object memory that was allocated.
|
||||
*/
|
||||
void obj_Cleanup(void);
|
||||
|
||||
#endif /* RGBDS_LINK_OBJECT_H */
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
/*
|
||||
* This file is part of RGBDS.
|
||||
*
|
||||
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
|
||||
* Copyright (c) 1997-2019, Carsten Sorensen and RGBDS contributors.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/* Outputting the result of linking */
|
||||
#ifndef RGBDS_LINK_OUTPUT_H
|
||||
#define RGBDS_LINK_OUTPUT_H
|
||||
|
||||
void out_Setname(char *tzOutputfile);
|
||||
void out_SetOverlayname(char *tzOverlayfile);
|
||||
void Output(void);
|
||||
#include <stdint.h>
|
||||
|
||||
#include "link/section.h"
|
||||
|
||||
void out_AddSection(struct Section const *section);
|
||||
|
||||
void out_WriteFiles(void);
|
||||
|
||||
#endif /* RGBDS_LINK_OUTPUT_H */
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
/*
|
||||
* This file is part of RGBDS.
|
||||
*
|
||||
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
|
||||
* Copyright (c) 1997-2019, Carsten Sorensen and RGBDS contributors.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/* Applying patches to SECTIONs */
|
||||
#ifndef RGBDS_LINK_PATCH_H
|
||||
#define RGBDS_LINK_PATCH_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void Patch(void);
|
||||
extern int32_t nPC;
|
||||
/**
|
||||
* Applies all SECTIONs' patches to them
|
||||
*/
|
||||
void patch_ApplyPatches(void);
|
||||
|
||||
#endif /* RGBDS_LINK_PATCH_H */
|
||||
|
||||
@@ -1,30 +1,34 @@
|
||||
/*
|
||||
* This file is part of RGBDS.
|
||||
*
|
||||
* Copyright (c) 2017-2018, Antonio Nino Diaz and RGBDS contributors.
|
||||
* Copyright (c) 1997-2019, Carsten Sorensen and RGBDS contributors.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/* Parsing a linker script */
|
||||
#ifndef RGBDS_LINK_SCRIPT_H
|
||||
#define RGBDS_LINK_SCRIPT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "helpers.h"
|
||||
struct SectionPlacement {
|
||||
struct Section *section;
|
||||
uint16_t org;
|
||||
uint32_t bank;
|
||||
};
|
||||
|
||||
noreturn_ void script_fatalerror(const char *fmt, ...);
|
||||
extern uint64_t script_lineNo;
|
||||
|
||||
void script_Parse(const char *path);
|
||||
/**
|
||||
* Parses the linker script to return the next section constraint
|
||||
* @return A pointer to a struct, or NULL on EOF. The pointer shouldn't be freed
|
||||
*/
|
||||
struct SectionPlacement *script_NextSection(void);
|
||||
|
||||
void script_IncludeFile(const char *path);
|
||||
int32_t script_IncludeDepthGet(void);
|
||||
void script_IncludePop(void);
|
||||
|
||||
void script_InitSections(void);
|
||||
void script_SetCurrentSectionType(const char *type, uint32_t bank);
|
||||
void script_SetAddress(uint32_t addr);
|
||||
void script_SetAlignment(uint32_t alignment);
|
||||
void script_OutputSection(const char *section_name);
|
||||
/**
|
||||
* `free`s all assignment memory that was allocated.
|
||||
*/
|
||||
void script_Cleanup(void);
|
||||
|
||||
#endif /* RGBDS_LINK_SCRIPT_H */
|
||||
|
||||
112
include/link/section.h
Normal file
112
include/link/section.h
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* This file is part of RGBDS.
|
||||
*
|
||||
* Copyright (c) 1997-2019, Carsten Sorensen and RGBDS contributors.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/* Declarations manipulating symbols */
|
||||
#ifndef RGBDS_LINK_SECTION_H
|
||||
#define RGBDS_LINK_SECTION_H
|
||||
|
||||
/* GUIDELINE: external code MUST NOT BE AWARE of the data structure used!! */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "link/main.h"
|
||||
|
||||
#include "linkdefs.h"
|
||||
|
||||
struct AttachedSymbol {
|
||||
struct Symbol *symbol;
|
||||
struct AttachedSymbol *next;
|
||||
};
|
||||
|
||||
struct Patch {
|
||||
char *fileName;
|
||||
int32_t lineNo;
|
||||
int32_t offset;
|
||||
enum PatchType type;
|
||||
int32_t rpnSize;
|
||||
uint8_t *rpnExpression;
|
||||
};
|
||||
|
||||
struct Section {
|
||||
/* Info contained in the object files */
|
||||
char *name;
|
||||
uint16_t size;
|
||||
enum SectionType type;
|
||||
bool isAddressFixed;
|
||||
uint16_t org;
|
||||
bool isBankFixed;
|
||||
uint32_t bank;
|
||||
bool isAlignFixed;
|
||||
uint16_t alignMask;
|
||||
uint8_t *data; /* Array of size `size`*/
|
||||
uint32_t nbPatches;
|
||||
struct Patch *patches;
|
||||
/* Extra info computed during linking */
|
||||
struct Symbol **fileSymbols;
|
||||
uint32_t nbSymbols;
|
||||
struct Symbol const **symbols;
|
||||
};
|
||||
|
||||
extern uint16_t startaddr[];
|
||||
extern uint16_t maxsize[];
|
||||
extern uint32_t bankranges[][2];
|
||||
extern char const * const typeNames[SECTTYPE_INVALID];
|
||||
|
||||
/**
|
||||
* Computes a memory region's end address (last byte), eg. 0x7FFF
|
||||
* @return The address of the last byte in that memory region
|
||||
*/
|
||||
static inline uint16_t endaddr(enum SectionType type)
|
||||
{
|
||||
return startaddr[type] + maxsize[type] - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a memory region's number of banks
|
||||
* @return The number of banks, 1 for regions without banking
|
||||
*/
|
||||
static inline uint32_t nbbanks(enum SectionType type)
|
||||
{
|
||||
return bankranges[type][1] - bankranges[type][0] + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute a callback for each section currently registered.
|
||||
* This is to avoid exposing the data structure in which sections are stored.
|
||||
* @param callback The function to call for each structure;
|
||||
* the first argument will be a pointer to the structure,
|
||||
* the second argument will be the pointer `arg`.
|
||||
* @param arg A pointer which will be passed to all calls to `callback`.
|
||||
*/
|
||||
void sect_ForEach(void (*callback)(struct Section *, void *), void *arg);
|
||||
|
||||
/**
|
||||
* Registers a section to be processed.
|
||||
* @param section The section to register.
|
||||
*/
|
||||
void sect_AddSection(struct Section *section);
|
||||
|
||||
/**
|
||||
* Finds a section by its name.
|
||||
* @param name The name of the section to look for
|
||||
* @return A pointer to the section, or NULL if it wasn't found
|
||||
*/
|
||||
struct Section *sect_GetSection(char const *name);
|
||||
|
||||
/**
|
||||
* `free`s all section memory that was allocated.
|
||||
*/
|
||||
void sect_CleanupSections(void);
|
||||
|
||||
/**
|
||||
* Checks if all sections meet reasonable criteria, such as max size
|
||||
*/
|
||||
void sect_DoSanityChecks(void);
|
||||
|
||||
#endif /* RGBDS_LINK_SECTION_H */
|
||||
@@ -1,21 +1,59 @@
|
||||
/*
|
||||
* This file is part of RGBDS.
|
||||
*
|
||||
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
|
||||
* Copyright (c) 1997-2019, Carsten Sorensen and RGBDS contributors.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/* Declarations manipulating symbols */
|
||||
#ifndef RGBDS_LINK_SYMBOL_H
|
||||
#define RGBDS_LINK_SYMBOL_H
|
||||
|
||||
/* GUIDELINE: external code MUST NOT BE AWARE of the data structure used!! */
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void sym_Init(void);
|
||||
void sym_CreateSymbol(char *tzName, int32_t nValue, int32_t nBank,
|
||||
char *tzObjFileName, char *tzFileName,
|
||||
uint32_t nFileLine);
|
||||
int32_t sym_GetValue(struct sPatch *pPatch, char *tzName);
|
||||
int32_t sym_GetBank(struct sPatch *pPatch, char *tzName);
|
||||
#include "linkdefs.h"
|
||||
|
||||
struct Symbol {
|
||||
/* Info contained in the object files */
|
||||
char *name;
|
||||
enum SymbolType type;
|
||||
char const *objFileName;
|
||||
char *fileName;
|
||||
int32_t lineNo;
|
||||
int32_t sectionID;
|
||||
union {
|
||||
int32_t offset;
|
||||
int32_t value;
|
||||
};
|
||||
/* Extra info computed during linking */
|
||||
struct Section *section;
|
||||
};
|
||||
|
||||
/*
|
||||
* Execute a callback for each symbol currently registered.
|
||||
* This is done to avoid exposing the data structure in which symbol are stored.
|
||||
* @param callback The function to call for each symbol;
|
||||
* the first argument will be a pointer to the symbol,
|
||||
* the second argument will be the pointer `arg`.
|
||||
* @param arg A pointer which will be passed to all calls to `callback`.
|
||||
*/
|
||||
void sym_ForEach(void (*callback)(struct Symbol *, void *), void *arg);
|
||||
|
||||
void sym_AddSymbol(struct Symbol *symbol);
|
||||
|
||||
/**
|
||||
* Finds a symbol in all the defined symbols.
|
||||
* @param name The name of the symbol to look for
|
||||
* @return A pointer to the symbol, or NULL if not found.
|
||||
*/
|
||||
struct Symbol *sym_GetSymbol(char const *name);
|
||||
|
||||
/**
|
||||
* `free`s all symbol memory that was allocated.
|
||||
*/
|
||||
void sym_CleanupSymbols(void);
|
||||
|
||||
#endif /* RGBDS_LINK_SYMBOL_H */
|
||||
|
||||
Reference in New Issue
Block a user