Implement INCLUDE keyword in linker scripts

This commit is contained in:
ISSOtm
2019-10-11 18:54:25 +02:00
parent 5496c2e76f
commit 9e33cc998f

View File

@@ -13,6 +13,60 @@
FILE *linkerScript; FILE *linkerScript;
static uint32_t lineNo;
static struct {
FILE *file;
uint32_t lineNo;
char const *name;
} *fileStack;
static uint32_t fileStackSize;
static uint32_t fileStackIndex;
static void pushFile(char const *newFileName)
{
if (fileStackIndex == UINT32_MAX)
errx(1, "%s(%u): INCLUDE recursion limit reached",
linkerScriptName, lineNo);
if (fileStackIndex == fileStackSize) {
if (!fileStackSize) /* Init file stack */
fileStackSize = 4;
fileStackSize *= 2;
fileStack = realloc(fileStack,
sizeof(*fileStack) * fileStackSize);
if (!fileStack)
err(1, "%s(%u): Internal INCLUDE error",
linkerScriptName, lineNo);
}
fileStack[fileStackIndex].file = linkerScript;
fileStack[fileStackIndex].lineNo = lineNo;
fileStack[fileStackIndex].name = linkerScriptName;
fileStackIndex++;
linkerScript = fopen(newFileName, "r");
if (!linkerScript)
err(1, "%s(%u): Could not open \"%s\"",
linkerScriptName, lineNo, newFileName);
lineNo = 1;
linkerScriptName = newFileName;
}
static bool popFile(void)
{
if (!fileStackIndex)
return false;
fileStackIndex--;
linkerScript = fileStack[fileStackIndex].file;
lineNo = fileStack[fileStackIndex].lineNo;
linkerScriptName = fileStack[fileStackIndex].name;
return true;
}
static inline bool isWhiteSpace(int c) static inline bool isWhiteSpace(int c)
{ {
return c == ' ' || c == '\t'; return c == ' ' || c == '\t';
@@ -69,13 +123,23 @@ enum LinkerScriptTokenType {
TOKEN_NEWLINE, TOKEN_NEWLINE,
TOKEN_COMMAND, TOKEN_COMMAND,
TOKEN_BANK, TOKEN_BANK,
TOKEN_INCLUDE,
TOKEN_NUMBER, TOKEN_NUMBER,
TOKEN_SECTION, TOKEN_STRING,
TOKEN_EOF, TOKEN_EOF,
TOKEN_INVALID TOKEN_INVALID
}; };
char const *tokenTypes[] = {
[TOKEN_NEWLINE] = "newline",
[TOKEN_COMMAND] = "command",
[TOKEN_BANK] = "bank command",
[TOKEN_NUMBER] = "number",
[TOKEN_STRING] = "string",
[TOKEN_EOF] = "end of file"
};
enum LinkerScriptCommand { enum LinkerScriptCommand {
COMMAND_ORG, COMMAND_ORG,
COMMAND_ALIGN, COMMAND_ALIGN,
@@ -98,8 +162,6 @@ static char const * const commands[] = {
[COMMAND_ALIGN] = "ALIGN" [COMMAND_ALIGN] = "ALIGN"
}; };
static uint32_t lineNo;
static int readChar(FILE *file) static int readChar(FILE *file)
{ {
int curchar = getc_unlocked(file); int curchar = getc_unlocked(file);
@@ -115,7 +177,7 @@ static struct LinkerScriptToken const *nextToken(void)
int curchar; int curchar;
/* If the token has a string, make sure to avoid leaking it */ /* If the token has a string, make sure to avoid leaking it */
if (token.type == TOKEN_SECTION) if (token.type == TOKEN_STRING)
free(token.attr.string); free(token.attr.string);
/* Skip initial whitespace... */ /* Skip initial whitespace... */
@@ -140,8 +202,8 @@ static struct LinkerScriptToken const *nextToken(void)
if (curchar == '\r') if (curchar == '\r')
readChar(linkerScript); /* Read and discard LF */ readChar(linkerScript); /* Read and discard LF */
} else if (curchar == '"') { } else if (curchar == '"') {
/* If we have a string start, this is a section name */ /* If we have a string start, this is a string */
token.type = TOKEN_SECTION; token.type = TOKEN_STRING;
token.attr.string = NULL; /* Force initial alloc */ token.attr.string = NULL; /* Force initial alloc */
size_t size = 0; size_t size = 0;
@@ -160,7 +222,7 @@ static struct LinkerScriptToken const *nextToken(void)
token.attr.string = realloc(token.attr.string, token.attr.string = realloc(token.attr.string,
capacity); capacity);
if (!token.attr.string) if (!token.attr.string)
err(1, "%s: Failed to allocate memory for section name", err(1, "%s: Failed to allocate memory for string",
__func__); __func__);
} }
token.attr.string[size++] = curchar; token.attr.string[size++] = curchar;
@@ -217,6 +279,12 @@ static struct LinkerScriptToken const *nextToken(void)
} }
} }
if (token.type == TOKEN_INVALID) {
/* Try to match an include token */
if (!strcmp("INCLUDE", str))
token.type = TOKEN_INCLUDE;
}
if (token.type == TOKEN_INVALID) { if (token.type == TOKEN_INVALID) {
/* None of the strings matched, do we have a number? */ /* None of the strings matched, do we have a number? */
if (tryParseNumber(str, &token.attr.number)) if (tryParseNumber(str, &token.attr.number))
@@ -259,6 +327,7 @@ static void processCommand(enum LinkerScriptCommand command, uint16_t arg,
enum LinkerScriptParserState { enum LinkerScriptParserState {
PARSER_FIRSTTIME, PARSER_FIRSTTIME,
PARSER_LINESTART, PARSER_LINESTART,
PARSER_INCLUDE, /* After an INCLUDE token */
PARSER_LINEEND PARSER_LINEEND
}; };
@@ -318,17 +387,22 @@ struct SectionPlacement *script_NextSection(void)
trap_; trap_;
case TOKEN_EOF: case TOKEN_EOF:
return NULL; if (!popFile())
return NULL;
parserState = PARSER_LINEEND;
break;
case TOKEN_NUMBER: case TOKEN_NUMBER:
errx(1, "%s(%u): stray number", errx(1, "%s(%u): stray number \"%u\"",
linkerScriptName, lineNo); linkerScriptName, lineNo,
token->attr.number);
case TOKEN_NEWLINE: case TOKEN_NEWLINE:
lineNo++; lineNo++;
break; break;
case TOKEN_SECTION: /* A stray string is a section name */
case TOKEN_STRING:
parserState = PARSER_LINEEND; parserState = PARSER_LINEEND;
if (type == SECTTYPE_INVALID) if (type == SECTTYPE_INVALID)
@@ -398,18 +472,36 @@ struct SectionPlacement *script_NextSection(void)
if (token->type != TOKEN_NUMBER) if (token->type != TOKEN_NUMBER)
goto lineend; goto lineend;
break; break;
case TOKEN_INCLUDE:
parserState = PARSER_INCLUDE;
break;
} }
break; break;
case PARSER_INCLUDE:
if (token->type != TOKEN_STRING)
errx(1, "%s(%u): Expected a file name after INCLUDE",
linkerScriptName, lineNo);
/* Switch to that file */
pushFile(token->attr.string);
parserState = PARSER_LINESTART;
break;
case PARSER_LINEEND: case PARSER_LINEEND:
lineend: lineend:
if (token->type == TOKEN_EOF)
return NULL;
else if (token->type != TOKEN_NEWLINE)
errx(1, "Linkerscript line %u: Unexpected token at the end",
lineNo);
lineNo++; lineNo++;
parserState = PARSER_LINESTART; parserState = PARSER_LINESTART;
if (token->type == TOKEN_EOF) {
if (!popFile())
return NULL;
parserState = PARSER_LINEEND;
} else if (token->type != TOKEN_NEWLINE)
errx(1, "%s(%u): Unexpected %s at the end of the line",
linkerScriptName, lineNo,
tokenTypes[token->type]);
break; break;
} }
} }