Merge pull request #161 from AntonioND/an/linkerscript-include

Add support for including files in linkerscript

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
This commit is contained in:
Antonio Niño Díaz
2017-04-09 17:19:13 +01:00
17 changed files with 167 additions and 75 deletions

View File

@@ -17,8 +17,16 @@
#ifndef RGBDS_LINK_SCRIPT_H
#define RGBDS_LINK_SCRIPT_H
#include "extern/stdnoreturn.h"
noreturn void script_fatalerror(const char *fmt, ...);
void script_Parse(const char *path);
void script_IncludeFile(const char *path);
int script_IncludeDepthGet(void);
void script_IncludePop(void);
void script_InitSections(void);
void script_SetCurrentSectionType(const char *type, unsigned int bank);
void script_SetAddress(unsigned int addr);

View File

@@ -20,8 +20,6 @@ int cldefines_index;
int cldefines_size;
char **cldefines;
char *progname;
clock_t nStartClock, nEndClock;
SLONG nLineNo;
ULONG nTotalLines, nPass, nPC, nIFDepth, nErrors;
@@ -301,8 +299,6 @@ main(int argc, char *argv[])
if (argc == 1)
usage();
progname = "rgbasm";
/* yydebug=1; */
DefaultOptions.gbgfx[0] = '0';

10
src/extern/err.c vendored
View File

@@ -26,11 +26,9 @@
#include <stdlib.h>
#include "extern/err.h"
extern char *progname;
void rgbds_vwarn(const char *fmt, va_list ap)
{
fprintf (stderr, "%s: warning", progname);
fprintf (stderr, "warning");
if (fmt) {
fputs (": ", stderr);
vfprintf(stderr, fmt, ap);
@@ -41,7 +39,7 @@ void rgbds_vwarn(const char *fmt, va_list ap)
void rgbds_vwarnx(const char *fmt, va_list ap)
{
fprintf (stderr, "%s: warning", progname);
fprintf (stderr, "warning");
if (fmt) {
fputs (": ", stderr);
vfprintf(stderr, fmt, ap);
@@ -51,7 +49,7 @@ void rgbds_vwarnx(const char *fmt, va_list ap)
noreturn void rgbds_verr(int status, const char *fmt, va_list ap)
{
fprintf (stderr, "%s: error", progname);
fprintf (stderr, "error");
if (fmt) {
fputs (": ", stderr);
vfprintf(stderr, fmt, ap);
@@ -62,7 +60,7 @@ noreturn void rgbds_verr(int status, const char *fmt, va_list ap)
noreturn void rgbds_verrx(int status, const char *fmt, va_list ap)
{
fprintf (stderr, "%s: error", progname);
fprintf (stderr, "error");
if (fmt) {
fputs (": ", stderr);
vfprintf(stderr, fmt, ap);

View File

@@ -23,8 +23,6 @@
#include "extern/err.h"
char *progname;
static void
usage(void)
{
@@ -71,8 +69,6 @@ main(int argc, char *argv[])
int version; /* mask ROM version number */
int padvalue; /* to pad the rom with if it changes size */
progname = "rgbfix";
while ((ch = getopt(argc, argv, "Cci:jk:l:m:n:p:sr:t:v")) != -1) {
switch (ch) {
case 'C':

View File

@@ -19,8 +19,6 @@
#include <string.h>
#include "gfx/main.h"
char *progname;
static void
usage(void)
{
@@ -41,8 +39,6 @@ main(int argc, char *argv[])
char *ext;
const char *errmsg = "Warning: The PNG's %s setting is not the same as the setting defined on the command line.";
progname = "rgbgfx";
if (argc == 1) {
usage();
}

View File

@@ -445,6 +445,7 @@ AssignSections(void)
*/
if (tzLinkerscriptName) {
script_InitSections();
script_Parse(tzLinkerscriptName);
}

View File

@@ -16,22 +16,38 @@
%option noinput
%option nounput
%option yylineno
%{
#include <stdarg.h>
#include <unistd.h>
#include "extern/err.h"
#include "link/mylink.h"
#include "link/script.h"
#include "parser.h"
/* File include stack. */
#define MAX_INCLUDE_DEPTH 8
static int include_stack_ptr = 0;
static YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
static char include_path[MAX_INCLUDE_DEPTH][_MAX_PATH + 1];
static int include_line[MAX_INCLUDE_DEPTH];
static char linkerscript_path[_MAX_PATH + 1]; /* Base file */
%}
%%
\"([^\\\"]|\\.)*\" {
if (strlen(yytext) > sizeof(yylval.s) - 1)
errx(1, "String is too long: \"%s\"\n.", yytext);
script_fatalerror("String is too long: %s\n.", yytext);
if (strlen(yytext) < 3) /* 2 quotes + 1 character */
errx(1, "String \"%s\" is invalid\n.", yytext);
script_fatalerror("String %s is invalid\n.", yytext);
yytext++; /* ignore first quote */
strcpy(yylval.s, yytext);
@@ -62,13 +78,99 @@
(?i:ALIGN) { return COMMAND_ALIGN; }
(?i:ORG) { return COMMAND_ORG; }
(?i:INCLUDE) { return COMMAND_INCLUDE; }
"\n" { return NEWLINE; }
;.* { /* Ignore comments. A dot doesn't match newline. */ }
[[:space:]] { /* Ignore whitespace. */ }
. { errx(1, "Invalid character [%s]\n.", yytext); }
. { script_fatalerror("Invalid character [%s]\n.", yytext); }
%%
extern FILE *yyin;
void script_Parse(const char * path)
{
yyin = fopen(path, "r");
if (!yyin)
errx(1, "Error opening file! \"%s\"\n", path);
strncpy(linkerscript_path, path, sizeof(linkerscript_path));
linkerscript_path[sizeof(linkerscript_path) - 1] = '\0';
do {
yyparse();
} while (!feof(yyin));
fclose(yyin);
}
void script_IncludeFile(const char * path)
{
if (include_stack_ptr == (MAX_INCLUDE_DEPTH-1))
script_fatalerror("Includes nested too deeply.");
include_line[include_stack_ptr] = yylineno;
include_stack[include_stack_ptr] = YY_CURRENT_BUFFER;
include_stack_ptr++;
yyin = fopen(path, "r" );
if (!yyin)
script_fatalerror("Couldn't open file \"%s\"", path);
strncpy(include_path[include_stack_ptr], path, sizeof(include_path[0]));
include_path[include_stack_ptr][sizeof(include_path[0])-1] = '\0';
yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
yylineno = 0;
}
int script_IncludeDepthGet(void)
{
return include_stack_ptr;
}
void script_IncludePop(void)
{
fclose(yyin);
include_stack_ptr--;
yy_delete_buffer(YY_CURRENT_BUFFER);
yy_switch_to_buffer(include_stack[include_stack_ptr]);
yylineno = include_line[include_stack_ptr];
}
void script_PrintFileStack(void)
{
int i = include_stack_ptr;
include_line[i] = yylineno;
while (i > 0) {
fprintf(stderr, "%s(%d) -> ", include_path[i], include_line[i]);
i--;
}
fprintf(stderr, "%s(%d)", linkerscript_path, include_line[i]);
}
noreturn void script_fatalerror(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
fprintf(stderr, "error: ");
script_PrintFileStack();
fprintf(stderr, ":\n\t");
vfprintf(stderr, fmt, args);
fprintf(stderr, "\n");
va_end(args);
exit(1);
}

View File

@@ -24,8 +24,6 @@ SLONG options = 0;
SLONG fillchar = 0;
char *smartlinkstartsymbol;
char *progname;
/*
* Print the usagescreen
*
@@ -54,8 +52,6 @@ main(int argc, char *argv[])
if (argc == 1)
usage();
progname = "rgblink";
while ((ch = getopt(argc, argv, "l:m:n:o:O:p:s:tw")) != -1) {
switch (ch) {
case 'l':

View File

@@ -23,7 +23,7 @@
int yylex();
void yyerror(char *);
static int nline = 1;
extern int yylineno;
%}
%union { int i; char s[512]; }
@@ -37,6 +37,8 @@ static int nline = 1;
%token COMMAND_ALIGN
%token COMMAND_ORG
%token COMMAND_INCLUDE
%token NEWLINE
%start lines
@@ -49,8 +51,8 @@ lines:
;
line:
/* empty */ { nline++; }
| statement { nline++; }
/* empty */
| statement
;
statement:
@@ -59,11 +61,11 @@ statement:
script_SetCurrentSectionType($1, 0);
}
| SECTION_NONBANKED INTEGER {
errx(1, "%d:Trying to assign a bank to a non-banked section.\n", nline);
script_fatalerror("Trying to assign a bank to a non-banked section.\n");
}
| SECTION_BANKED {
errx(1, "%d:Banked section without assigned bank.\n", nline);
script_fatalerror("Banked section without assigned bank.\n");
}
| SECTION_BANKED INTEGER {
script_SetCurrentSectionType($1, $2);
@@ -74,13 +76,13 @@ statement:
script_SetAlignment($2);
}
| COMMAND_ALIGN {
errx(1, "%d:ALIGN keyword needs an argument.\n", nline);
script_fatalerror("ALIGN keyword needs an argument.\n");
}
| COMMAND_ORG INTEGER {
script_SetAddress($2);
}
| COMMAND_ORG {
errx(1, "%d:ORG keyword needs an argument.\n", nline);
script_fatalerror("ORG keyword needs an argument.\n");
}
/* Section name */
@@ -88,6 +90,11 @@ statement:
script_OutputSection($1);
}
/* Include file */
| COMMAND_INCLUDE STRING {
script_IncludeFile($2);
}
/* End */
;
@@ -96,33 +103,18 @@ statement:
extern int yylex();
extern int yyparse();
extern FILE *yyin;
int yywrap (void)
int yywrap(void)
{
return 1;
if (script_IncludeDepthGet() == 0)
return 1;
script_IncludePop();
return 0;
}
void yyerror(char *s)
{
errx(1, "%d:Linkerscript parse error: \"%s\"\n", nline, s);
}
void script_Parse(const char *path)
{
script_InitSections();
FILE *f = fopen(path, "r");
if (!f)
errx(1, "Error opening file! \"%s\"\n", path);
yyin = f;
do {
yyparse();
} while (!feof(yyin));
fclose(f);
script_fatalerror("Linkerscript parse error: \"%s\"\n", s);
}

View File

@@ -12,7 +12,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd March 27, 2017
.Dd April 8, 2017
.Dt RGBLINK 5
.Os RGBDS Manual
.Sh NAME
@@ -34,35 +34,42 @@ Any line can contain a comment starting with
that ends at the end of the line:
.Pp
ROMX $F ; This is a comment
"Functions to read array"
ALIGN 8
"Array aligned to 256 bytes"
"Functions to read array"
ALIGN 8
"Array aligned to 256 bytes"
WRAMX 2
"Some variables"
"Some variables"
.Pp
Numbers can be in decimal or hexadecimal format (the prefix is
.Ql $ ) .
It is an error if any bank or command is found before setting a bank.
.Pp
The possible bank types are: ROM0, ROMX, VRAM, WRAM0, WRAMX, OAM and HRAM.
Types ROMX, VRAM, WRAMX and SRAM are banked, which means that it is needed to
specify a bank after the type.
Files can be included by using the
.Ar INCLUDE No keyword followed by a string with the path of the file that has
to be included.
.Pp
The possible bank types are:
.Sy ROM0 , ROMX , VRAM , WRAM0 , WRAMX , OAM No and Sy HRAM .
Types
.Sy ROMX , VRAM , WRAMX No and Sy SRAM No are banked, which means that it is
needed to specify a bank after the type.
.Pp
When a new bank statement is found, sections found after it will be placed
right from the beginning of that bank.
If the linkerscript switches to a different bank and then it comes back to the
previous one it will continue from the last address that was used.
.Pp
The only two commands are ORG and ALIGN:
The only two commands are
.Ar ORG No and Ar ALIGN :
.Bl -bullet
.It
ORG sets the address in which new sections will be placed.
.Ar ORG No sets the address in which new sections will be placed.
It can not be lower than the current address.
.It
ALIGN will increase the address until it is aligned to the specified boundary
(it tries to set to 0 the number of bits specified after the command: ALIGN 8
will align to $100).
.Ar ALIGN No will increase the address until it is aligned to the specified
boundary (it tries to set to 0 the number of bits specified after the command:
.Ar ALIGN No 8 No will align to No $100 ) .
.El
.Pp
Note: The bank, alignment, address and type of sections can be specified both

View File

@@ -1,3 +1,3 @@
ERROR: undefined-dot.asm(3):
'.' not defined
rgbasm: error: Assembly aborted in pass 2 (1 errors)!
error: Assembly aborted in pass 2 (1 errors)!

View File

@@ -1 +1 @@
rgblink: error: Unable to place 'r0b' (ROM0 section) anywhere
error: Unable to place 'r0b' (ROM0 section) anywhere

View File

@@ -1 +1 @@
rgblink: error: ROMX sections can't be used with option -t.
error: ROMX sections can't be used with option -t.

View File

@@ -1 +1 @@
rgblink: error: VRAM bank 1 can't be used with option -w.
error: VRAM bank 1 can't be used with option -w.

View File

@@ -1 +1 @@
rgblink: error: Unable to place 'v1' (VRAM section) in any bank
error: Unable to place 'v1' (VRAM section) in any bank

View File

@@ -1 +1 @@
rgblink: error: Unable to place 'w0b' (WRAM0 section) anywhere
error: Unable to place 'w0b' (WRAM0 section) anywhere

View File

@@ -1 +1 @@
rgblink: error: WRAMX sections can't be used with option -w.
error: WRAMX sections can't be used with option -w.