mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 10:12:06 +00:00
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:
@@ -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);
|
||||
|
||||
@@ -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
10
src/extern/err.c
vendored
@@ -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);
|
||||
|
||||
@@ -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':
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@ AssignSections(void)
|
||||
*/
|
||||
|
||||
if (tzLinkerscriptName) {
|
||||
script_InitSections();
|
||||
script_Parse(tzLinkerscriptName);
|
||||
}
|
||||
|
||||
|
||||
108
src/link/lexer.l
108
src/link/lexer.l
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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':
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)!
|
||||
|
||||
@@ -1 +1 @@
|
||||
rgblink: error: Unable to place 'r0b' (ROM0 section) anywhere
|
||||
error: Unable to place 'r0b' (ROM0 section) anywhere
|
||||
|
||||
@@ -1 +1 @@
|
||||
rgblink: error: ROMX sections can't be used with option -t.
|
||||
error: ROMX sections can't be used with option -t.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -1 +1 @@
|
||||
rgblink: error: Unable to place 'v1' (VRAM section) in any bank
|
||||
error: Unable to place 'v1' (VRAM section) in any bank
|
||||
|
||||
@@ -1 +1 @@
|
||||
rgblink: error: Unable to place 'w0b' (WRAM0 section) anywhere
|
||||
error: Unable to place 'w0b' (WRAM0 section) anywhere
|
||||
|
||||
@@ -1 +1 @@
|
||||
rgblink: error: WRAMX sections can't be used with option -w.
|
||||
error: WRAMX sections can't be used with option -w.
|
||||
|
||||
Reference in New Issue
Block a user