ref: 9e33cc998fb889dc057f7a67001761bad085a23d
parent: 5496c2e76f82cee8fdc747bc041f493470752b48
author: ISSOtm <[email protected]>
date: Fri Oct 11 14:54:25 EDT 2019
Implement INCLUDE keyword in linker scripts
--- a/src/link/script.c
+++ b/src/link/script.c
@@ -13,6 +13,60 @@
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)
{
return c == ' ' || c == '\t';
@@ -69,13 +123,23 @@
TOKEN_NEWLINE,
TOKEN_COMMAND,
TOKEN_BANK,
+ TOKEN_INCLUDE,
TOKEN_NUMBER,
- TOKEN_SECTION,
+ TOKEN_STRING,
TOKEN_EOF,
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 {
COMMAND_ORG,
COMMAND_ALIGN,
@@ -98,8 +162,6 @@
[COMMAND_ALIGN] = "ALIGN"
};
-static uint32_t lineNo;
-
static int readChar(FILE *file)
{
int curchar = getc_unlocked(file);
@@ -115,7 +177,7 @@
int curchar;
/* 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);
/* Skip initial whitespace... */
@@ -140,8 +202,8 @@
if (curchar == '\r')
readChar(linkerScript); /* Read and discard LF */
} else if (curchar == '"') {
- /* If we have a string start, this is a section name */
- token.type = TOKEN_SECTION;
+ /* If we have a string start, this is a string */
+ token.type = TOKEN_STRING;
token.attr.string = NULL; /* Force initial alloc */
size_t size = 0;
@@ -160,7 +222,7 @@
token.attr.string = realloc(token.attr.string,
capacity);
if (!token.attr.string)
- err(1, "%s: Failed to allocate memory for section name",
+ err(1, "%s: Failed to allocate memory for string",
__func__);
}
token.attr.string[size++] = curchar;
@@ -218,6 +280,12 @@
}
if (token.type == TOKEN_INVALID) {
+ /* Try to match an include token */
+ if (!strcmp("INCLUDE", str))
+ token.type = TOKEN_INCLUDE;
+ }
+
+ if (token.type == TOKEN_INVALID) {
/* None of the strings matched, do we have a number? */
if (tryParseNumber(str, &token.attr.number))
token.type = TOKEN_NUMBER;
@@ -259,6 +327,7 @@
enum LinkerScriptParserState {
PARSER_FIRSTTIME,
PARSER_LINESTART,
+ PARSER_INCLUDE, /* After an INCLUDE token */
PARSER_LINEEND
};
@@ -318,17 +387,22 @@
trap_;
case TOKEN_EOF:
- return NULL;
+ if (!popFile())
+ return NULL;
+ parserState = PARSER_LINEEND;
+ break;
case TOKEN_NUMBER:
- errx(1, "%s(%u): stray number",
- linkerScriptName, lineNo);
+ errx(1, "%s(%u): stray number \"%u\"",
+ linkerScriptName, lineNo,
+ token->attr.number);
case TOKEN_NEWLINE:
lineNo++;
break;
- case TOKEN_SECTION:
+ /* A stray string is a section name */
+ case TOKEN_STRING:
parserState = PARSER_LINEEND;
if (type == SECTTYPE_INVALID)
@@ -398,18 +472,36 @@
if (token->type != TOKEN_NUMBER)
goto lineend;
break;
+
+ case TOKEN_INCLUDE:
+ parserState = PARSER_INCLUDE;
+ 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:
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++;
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;
}
}