ref: f8f67fcbceea754bba2268be11da9b7aba7a285a
dir: /src/link/object.c/
/* * This file is part of RGBDS. * * Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors. * * SPDX-License-Identifier: MIT */ /* * Here we have the routines that read an objectfile */ #include <ctype.h> #include <errno.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "common.h" #include "extern/err.h" #include "link/assign.h" #include "link/mylink.h" #include "link/main.h" struct sSymbol **tSymbols; struct sSection *pSections; struct sSection *pLibSections; uint8_t dummymem; uint8_t oReadLib; /* * Read 32-bit values with the correct endianness */ static int32_t readlong(FILE *f) { int32_t r; r = fgetc(f); r |= fgetc(f) << 8; r |= fgetc(f) << 16; r |= fgetc(f) << 24; return r; } /* * Read a NULL terminated string from a file */ int32_t readasciiz(char **dest, FILE *f) { size_t r = 0; size_t bufferLength = 16; char *start = malloc(bufferLength); char *s = start; if (!s) err(1, "%s: Couldn't allocate memory", __func__); while (((*s++) = fgetc(f)) != 0) { r += 1; if (r >= bufferLength) { bufferLength *= 2; start = realloc(start, bufferLength); if (!start) { err(1, "%s: Couldn't allocate memory", __func__); } s = start + r; } } *dest = start; return (r + 1); } /* * Allocate a new section and link it into the list */ struct sSection *AllocSection(void) { struct sSection **ppSections; if (oReadLib == 1) ppSections = &pLibSections; else ppSections = &pSections; while (*ppSections) ppSections = &((*ppSections)->pNext); *ppSections = malloc(sizeof **ppSections); if (!*ppSections) err(1, "%s: Couldn't allocate memory", __func__); (*ppSections)->tSymbols = tSymbols; (*ppSections)->pNext = NULL; (*ppSections)->pPatches = NULL; (*ppSections)->oAssigned = 0; return *ppSections; } /* * Read a symbol from a file */ struct sSymbol *obj_ReadSymbol(FILE *f, char *tzObjectfile) { struct sSymbol *pSym; pSym = malloc(sizeof(*pSym)); if (!pSym) err(1, "%s: Couldn't allocate memory", __func__); readasciiz(&pSym->pzName, f); pSym->Type = (enum eSymbolType)fgetc(f); pSym->pzObjFileName = tzObjectfile; if (pSym->Type != SYM_IMPORT) { readasciiz(&pSym->pzFileName, f); pSym->nFileLine = readlong(f); pSym->nSectionID = readlong(f); pSym->nOffset = readlong(f); } return pSym; } /* * RGB object reader routines */ struct sSection *obj_ReadRGBSection(FILE *f) { struct sSection *pSection; char *pzName; readasciiz(&pzName, f); if (IsSectionNameInUse(pzName)) errx(1, "Section name \"%s\" is already in use.", pzName); pSection = AllocSection(); pSection->pzName = pzName; pSection->nByteSize = readlong(f); pSection->Type = (enum eSectionType)fgetc(f); pSection->nOrg = readlong(f); pSection->nBank = readlong(f); pSection->nAlign = readlong(f); if ((options & OPT_TINY) && (pSection->Type == SECT_ROMX)) errx(1, "ROMX sections can't be used with option -t."); if ((options & OPT_CONTWRAM) && (pSection->Type == SECT_WRAMX)) errx(1, "WRAMX sections can't be used with options -w or -d."); if (options & OPT_DMG_MODE) { /* WRAMX sections are checked for OPT_CONTWRAM */ if (pSection->Type == SECT_VRAM && pSection->nBank == 1) errx(1, "VRAM bank 1 can't be used with option -d."); } uint32_t maxsize = 0; /* Verify that the section isn't too big */ switch (pSection->Type) { case SECT_ROM0: maxsize = (options & OPT_TINY) ? 0x8000 : 0x4000; break; case SECT_ROMX: maxsize = 0x4000; break; case SECT_VRAM: case SECT_SRAM: maxsize = 0x2000; break; case SECT_WRAM0: maxsize = (options & OPT_CONTWRAM) ? 0x2000 : 0x1000; break; case SECT_WRAMX: maxsize = 0x1000; break; case SECT_OAM: maxsize = 0xA0; break; case SECT_HRAM: maxsize = 0x7F; break; default: errx(1, "Section \"%s\" has an invalid section type.", pzName); break; } if (pSection->nByteSize > maxsize) { errx(1, "Section \"%s\" is bigger than the max size for that type: 0x%X > 0x%X", pzName, pSection->nByteSize, maxsize); } /* * If the section doesn't contain data, it is ready */ if ((pSection->Type != SECT_ROMX) && (pSection->Type != SECT_ROM0)) return pSection; /* If there is no data to read, exit */ if (pSection->nByteSize == 0) { /* Skip number of patches */ readlong(f); pSection->pData = &dummymem; return pSection; } pSection->pData = malloc(pSection->nByteSize); if (!pSection->pData) err(1, "%s: Couldn't allocate memory", __func__); int32_t nNumberOfPatches; struct sPatch **ppPatch, *pPatch; if (fread(pSection->pData, sizeof(uint8_t), pSection->nByteSize, f) != pSection->nByteSize) { err(1, "%s: Read error", __func__); } nNumberOfPatches = readlong(f); ppPatch = &pSection->pPatches; /* * And patches... */ while (nNumberOfPatches--) { pPatch = malloc(sizeof(*pPatch)); if (!pPatch) err(1, "%s: Couldn't allocate memory", __func__); *ppPatch = pPatch; readasciiz(&pPatch->pzFilename, f); pPatch->nLineNo = readlong(f); pPatch->nOffset = readlong(f); pPatch->Type = (enum ePatchType)fgetc(f); pPatch->nRPNSize = readlong(f); if (pPatch->nRPNSize > 0) { pPatch->pRPN = malloc(pPatch->nRPNSize); if (!pPatch->pRPN) { err(1, "%s: Couldn't allocate memory", __func__); } if (fread(pPatch->pRPN, sizeof(uint8_t), pPatch->nRPNSize, f) != pPatch->nRPNSize) { errx(1, "%s: Read error", __func__); } } else { pPatch->pRPN = NULL; } pPatch->pNext = NULL; ppPatch = &(pPatch->pNext); } return pSection; } void obj_ReadRGB(FILE *pObjfile, char *tzObjectfile) { struct sSection *pFirstSection; int32_t nNumberOfSymbols, nNumberOfSections, i; nNumberOfSymbols = readlong(pObjfile); nNumberOfSections = readlong(pObjfile); /* First comes the symbols */ if (nNumberOfSymbols) { tSymbols = malloc(nNumberOfSymbols * sizeof(*tSymbols)); if (!tSymbols) err(1, "%s: Couldn't allocate memory", __func__); for (i = 0; i < nNumberOfSymbols; i += 1) tSymbols[i] = obj_ReadSymbol(pObjfile, tzObjectfile); } else { tSymbols = (struct sSymbol **)&dummymem; } /* Next we have the sections */ pFirstSection = NULL; while (nNumberOfSections--) { struct sSection *pNewSection; pNewSection = obj_ReadRGBSection(pObjfile); pNewSection->nNumberOfSymbols = nNumberOfSymbols; if (pFirstSection == NULL) pFirstSection = pNewSection; } /* * Fill in the pSection entry in the symbolstructure. * This REALLY needs some cleaning up... but, hey, it works */ for (i = 0; i < nNumberOfSymbols; i += 1) { struct sSection *pConvSect = pFirstSection; if ((tSymbols[i]->Type != SYM_IMPORT) && (tSymbols[i]->nSectionID != -1)) { int32_t j = 0; while (j != tSymbols[i]->nSectionID) { j += 1; pConvSect = pConvSect->pNext; } tSymbols[i]->pSection = pConvSect; } else { tSymbols[i]->pSection = NULL; } } } /* * The main objectfileloadroutine (phew) */ void obj_ReadOpenFile(FILE *pObjfile, char *tzObjectfile) { char tzHeader[strlen(RGBDS_OBJECT_VERSION_STRING) + 1]; if (fread(tzHeader, sizeof(char), strlen(RGBDS_OBJECT_VERSION_STRING), pObjfile) != strlen(RGBDS_OBJECT_VERSION_STRING)) { errx(1, "%s: Read error", tzObjectfile); } tzHeader[strlen(RGBDS_OBJECT_VERSION_STRING)] = 0; if (strncmp(tzHeader, RGBDS_OBJECT_VERSION_STRING, strlen(RGBDS_OBJECT_VERSION_STRING)) == 0) { obj_ReadRGB(pObjfile, tzObjectfile); } else { int32_t i; for (i = 0; i < strlen(RGBDS_OBJECT_VERSION_STRING); i++) if (!isprint(tzHeader[i])) tzHeader[i] = '?'; errx(1, "%s: Invalid file or object file version [%s]", tzObjectfile, tzHeader); } } void obj_Readfile(char *tzObjectfile) { FILE *pObjfile; if (options & OPT_SMART_C_LINK) oReadLib = 1; else oReadLib = 0; pObjfile = fopen(tzObjectfile, "rb"); if (pObjfile == NULL) err(1, "Unable to open object '%s'", tzObjectfile); obj_ReadOpenFile(pObjfile, tzObjectfile); fclose(pObjfile); oReadLib = 0; } int32_t file_Length(FILE *f) { uint32_t r, p; p = ftell(f); fseek(f, 0, SEEK_END); r = ftell(f); fseek(f, p, SEEK_SET); return r; }