Created
September 15, 2019 14:48
-
-
Save ISSOtm/6e93a21c957509ed5161e9626cf9cca9 to your computer and use it in GitHub Desktop.
Tentative "ad-hoc" linkerscript parser for RGBDS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdlib.h> | |
#include <stdbool.h> | |
#include <stdint.h> | |
#include <string.h> | |
#include "link/main.h" | |
#include "link/script.h" | |
#include "link/section.h" | |
#include "extern/err.h" | |
struct SectionPlacement section; | |
static char const * const types[] = { | |
[SECTTYPE_ROM0] = "ROM0", | |
[SECTTYPE_ROMX] = "ROMX", | |
[SECTTYPE_VRAM] = "VRAM", | |
[SECTTYPE_SRAM] = "SRAM", | |
[SECTTYPE_WRAM0] = "WRAM0", | |
[SECTTYPE_WRAMX] = "WRAMX", | |
[SECTTYPE_OAM] = "OAM", | |
[SECTTYPE_HRAM] = "HRAM" | |
}; | |
/* Part of internal state, but has data that needs to be freed */ | |
static uint16_t *curaddr[SECTTYPE_INVALID]; | |
static bool firstTime = true; | |
struct SectionPlacement *script_NextSection(void) | |
{ | |
static uint64_t lineNo; | |
static enum SectionType type; | |
static uint32_t bank; | |
if (firstTime) { | |
firstTime = false; | |
/* Init search */ | |
for (enum SectionType type = 0; type < SECTTYPE_INVALID; | |
type++) { | |
curaddr[type] = | |
malloc(sizeof(*curaddr[type]) * nbbanks(type)); | |
if (!curaddr[type]) | |
err(1, "Failed to init linker script parsing"); | |
for (uint32_t i = 0; i < nbbanks(type); i++) | |
curaddr[type][type] = startaddr[type]; | |
} | |
lineNo = 1; | |
type = SECTTYPE_INVALID; | |
} | |
while (1) { | |
struct SectionPlacement *retptr = NULL; | |
char curchar; | |
/* Skip initial whitespace */ | |
do { | |
int _char = getc(linkerScript); | |
if (_char == EOF) { | |
if (!feof(linkerScript)) | |
goto error; | |
return NULL; | |
} | |
curchar = _char; | |
} while (curchar == ' ' || curchar == '\t'); | |
if (curchar == '"') { | |
/* If the first char is a quote, being a section decl */ | |
if (type == SECTTYPE_INVALID) | |
errx(1, "Section name encountered without a bank on line %u", | |
lineNo); | |
char *str; | |
if (fscanf(linkerScript, "%m[^\"\r\n]%c", | |
&str, &curchar) != 2 || curchar != '"') { | |
if (feof(linkerScript)) | |
errx(1, "Unterminated section name on line %u", | |
lineNo); | |
else | |
goto error; | |
} | |
struct Section *targetSect = sect_GetSection(str); | |
if (!targetSect) | |
errx(1, "Referenced unknown section \"%s\" on line %u", | |
str, lineNo); | |
section.section = targetSect; | |
section.address = curaddr[type][bank]; | |
section.bank = bank; | |
curaddr[type][bank] += targetSect->size; | |
free(str); | |
} else if (!strchr(";\n\r", curchar)) { | |
char *directive; | |
if (fscanf(linkerScript, "%m[^ \t;\r\n]%c", | |
&directive, &curchar) != 1) | |
goto error; | |
/* Try reading an argument number */ | |
bool hasArgument = false; | |
uint32_t argument; | |
if (curchar == ' ' || curchar == '\t') { | |
if (fscanf(linkerScript, "%*[ \t]%c", | |
&curchar) == 1 | |
&& !strchr(";\r\n", curchar)) { | |
hasArgument = true; | |
char const *format = "%x"; | |
if (curchar != '$') { | |
ungetc(curchar, linkerScript); | |
format = "%u"; | |
} | |
if (fscanf(linkerScript, format, | |
&argument) != 1) | |
errx(1, "Failed to parse argument on line %u", | |
lineNo); | |
} else if (!feof(linkerScript)) { | |
goto error; | |
} | |
} | |
if (!strcmp("ALIGN", directive)) { | |
/* Align current PC to the nearest boundary */ | |
} else if (!strcmp("ORG", directive)) { | |
/* Go to a certain address, but not backwards */ | |
} else { | |
/* New memory type! */ | |
enum SectionType newType = 0; | |
for ( ; newType < SECTTYPE_INVALID; newType++) { | |
if (!strcmp(types[newType], directive)) | |
break; | |
} | |
if (newType == SECTTYPE_INVALID) | |
errx(1, "Unknown directive \"%s\" on line %u", | |
directive, lineNo); | |
type = newType; | |
if (!hasArgument) { | |
bank = bankranges[type][0]; | |
if (bank != bankranges[type][1]) | |
errx(1, "Expected bank number for %s on line %u", | |
directive, lineNo); | |
} else if (argument < bankranges[type][0] | |
|| argument > bankranges[type][1]) { | |
errx(1, "Bank %u is not in range for type %s on line %u", | |
bank, directive, lineNo); | |
} | |
} | |
free(directive); | |
} else { | |
ungetc(curchar, linkerScript); | |
} | |
/* Read trailing whitespace and/or comment */ | |
if (fscanf(linkerScript, "%*[ \t]%c", &curchar) != 1) { | |
if (!feof(linkerScript)) | |
goto error; | |
} else if (curchar == ';') { | |
/* Comment: read until the end of the line or EOF */ | |
if (fscanf(linkerScript, "%*[^\r\n]%c", | |
&curchar) != 1) { | |
if (!feof(linkerScript)) | |
goto error; | |
else | |
curchar = '\n'; | |
} | |
} else { | |
errx(1, "Unexpected character '%c' on line %u", curchar, | |
lineNo); | |
} | |
/* Handle all possible line endings */ | |
if (curchar == '\r') { | |
int _char = getc(linkerScript); | |
if (_char != '\n') { | |
if (_char != EOF) | |
ungetc(_char, linkerScript); | |
else if (!feof(linkerScript)) | |
goto error; | |
} | |
} | |
if (retptr) | |
return retptr; | |
} | |
error: | |
err(1, "Unexpected failure while reading linker script on line %u", | |
lineNo); | |
} | |
void script_Cleanup(void) | |
{ | |
for (enum SectionType type = 0; type < SECTTYPE_INVALID; type++) | |
free(curaddr[type]); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* This file is part of RGBDS. | |
* | |
* 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> | |
struct SectionPlacement { | |
struct Section *section; | |
uint16_t address; | |
uint32_t bank; | |
}; | |
extern uint64_t script_lineNo; | |
/** | |
* 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); | |
/** | |
* `free`s all assignment memory that was allocated. | |
*/ | |
void script_Cleanup(void); | |
#endif /* RGBDS_LINK_SCRIPT_H */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment