From 22d4a10cb61566c0b696fd6accbad2a31a87358c Mon Sep 17 00:00:00 2001 From: AntonioND Date: Mon, 20 Mar 2017 23:13:29 +0000 Subject: [PATCH 1/4] Implement linkerscript parser Signed-off-by: AntonioND --- LICENSE | 6 +- Makefile | 19 ++++ include/link/assign.h | 7 ++ include/link/script.h | 29 ++++++ src/link/.gitignore | 2 + src/link/assign.c | 49 ++++++++++ src/link/lexer.l | 75 +++++++++++++++ src/link/parser.y | 123 ++++++++++++++++++++++++ src/link/script.c | 218 ++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 527 insertions(+), 1 deletion(-) create mode 100644 include/link/script.h create mode 100644 src/link/.gitignore create mode 100644 src/link/lexer.l create mode 100644 src/link/parser.y create mode 100644 src/link/script.c diff --git a/LICENSE b/LICENSE index a8d669a3..476a5e2d 100644 --- a/LICENSE +++ b/LICENSE @@ -11,7 +11,7 @@ released under the following license: This program is free software. It comes without any warranty, to the extent permitted by applicable law. You can redistribute it and/or modify it under the terms of the DO WHATEVER PUBLIC LICENSE - + Software originally created by Justin Lloyd @ http://otakunozoku.com/ @@ -20,6 +20,10 @@ under the ISC license; see the source file for the text of the license. rgbgfx was written by stag019, and is released under the ISC license. +Some files of rgblink were written by Antonio Niño Díaz, and they are relased +under the ISC license. The affected files have the appropriate license in the +header of the file. + The UTF-8 decoder in src/asm/charmap.c was written by Björn Höhrmann and is released under the MIT license. The remainder of charmap.c was written by stag019, and is released under the ISC license. diff --git a/Makefile b/Makefile index 071bdd10..dbbd7e47 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,12 @@ PNGFLAGS != ${PKG_CONFIG} --cflags libpng REALCFLAGS = ${CFLAGS} ${WARNFLAGS} ${PNGFLAGS} -Iinclude -g \ -std=c99 -D_POSIX_C_SOURCE=200809L +LFLAGS := --nounistd + +YACC := yacc +FLEX := flex +RM := rm -rf + # User-defined variables PREFIX = /usr/local BINPREFIX = ${PREFIX}/bin @@ -32,12 +38,15 @@ rgbasm_obj = \ rgblink_obj = \ src/link/assign.o \ + src/link/lexer.o \ src/link/library.o \ src/link/main.o \ src/link/mapfile.o \ src/link/object.o \ src/link/output.o \ src/link/patch.o \ + src/link/parser.o \ + src/link/script.o \ src/link/symbol.o \ src/extern/err.o @@ -60,6 +69,7 @@ clean: $Qrm -rf rgbfix rgbfix.exe ${rgbfix_obj} rgbfix.html $Qrm -rf rgbgfx rgbgfx.exe ${rgbgfx_obj} rgbgfx.html $Qrm -rf src/asm/asmy.c src/asm/asmy.h + $Qrm -rf src/link/lexer.c src/link/parser.c src/link/parser.h install: all $Qmkdir -p ${BINPREFIX} @@ -89,12 +99,21 @@ rgbgfx: ${rgbgfx_obj} .y.c: $Q${YACC} -d ${YFLAGS} -o $@ $< +.l.o: + $Q${RM} $*.c + $Q${FLEX} ${LFLAGS} -o $*.c $< + $Q${CC} ${REALCFLAGS} -c -o $@ $*.c + $Q${RM} $*.c + .c.o: $Q${CC} ${REALCFLAGS} -c -o $@ $< src/asm/locallex.o src/asm/globlex.o src/asm/lexer.o: src/asm/asmy.h src/asm/asmy.h: src/asm/asmy.c +src/link/lexer.o : src/link/parser.h +src/link/parser.h : src/link/parser.c + # Below is a target for the project maintainer to easily create win32 exes. # This is not for Windows users! # If you're building on Windows with Cygwin or Mingw, just follow the Unix diff --git a/include/link/assign.h b/include/link/assign.h index 5624b2f1..754e0906 100644 --- a/include/link/assign.h +++ b/include/link/assign.h @@ -1,6 +1,7 @@ #ifndef RGBDS_LINK_ASSIGN_H #define RGBDS_LINK_ASSIGN_H +#include "mylink.h" #include "types.h" enum eBankCount { @@ -34,4 +35,10 @@ extern void CreateSymbolTable(void); extern SLONG MaxBankUsed; extern SLONG MaxAvail[MAXBANKS]; +int +IsSectionSameTypeBankAndFloating(const char *name, enum eSectionType type, int bank); + +unsigned int +AssignSectionAddressByName(const char *name, unsigned int address); + #endif diff --git a/include/link/script.h b/include/link/script.h new file mode 100644 index 00000000..4e897cda --- /dev/null +++ b/include/link/script.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2017 Antonio Nino Diaz + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef RGBDS_LINK_SCRIPT_H +#define RGBDS_LINK_SCRIPT_H + +void script_Parse(const char *path); + +void script_InitSections(void); +void script_SetCurrentSectionType(const char *type, unsigned int bank); +void script_SetAddress(unsigned int addr); +void script_SetAlignment(unsigned int alignment); +void script_OutputSection(const char *section_name); + +#endif + diff --git a/src/link/.gitignore b/src/link/.gitignore new file mode 100644 index 00000000..d7814e41 --- /dev/null +++ b/src/link/.gitignore @@ -0,0 +1,2 @@ +parser.c +parser.h diff --git a/src/link/assign.c b/src/link/assign.c index 93d8a657..0c7a0c4b 100644 --- a/src/link/assign.c +++ b/src/link/assign.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "extern/err.h" #include "link/mylink.h" @@ -214,6 +215,54 @@ FindLargestSection(enum eSectionType type, bool bankFixed) return r; } +int +IsSectionSameTypeBankAndFloating(const char *name, enum eSectionType type, int bank) +{ + struct sSection *pSection; + + pSection = pSections; + while (pSection) { + if (pSection->oAssigned == 0) { + if (strcmp(pSection->pzName, name) == 0) { + /* Section must be floating in source */ + if (pSection->nOrg != -1 || pSection->nAlign != 1) + return 0; + /* It must have the same type in source and linkerscript */ + if (pSection->Type != type) + return 0; + /* Bank number must be unassigned in source or equal */ + if (pSection->nBank != -1 && pSection->nBank != bank) + return 0; + return 1; + } + } + pSection = pSection->pNext; + } + + errx(1, "Section \"%s\" not found (or already used).\n", name); +} + +unsigned int +AssignSectionAddressByName(const char *name, unsigned int address) +{ + struct sSection *pSection; + + pSection = pSections; + while (pSection) { + if (pSection->oAssigned == 0) { + if (strcmp(pSection->pzName, name) == 0) { + if (pSection->nOrg != -1 || pSection->nAlign != 1) + errx(1, "Section \"%s\" from linkerscript isn't floating.\n", name); + pSection->nOrg = address; + pSection->nAlign = -1; + return pSection->nByteSize; + } + } + pSection = pSection->pNext; + } + + errx(1, "Section \"%s\" not found (or already used).\n", name); +} bool VerifyAndSetBank(struct sSection *pSection) diff --git a/src/link/lexer.l b/src/link/lexer.l new file mode 100644 index 00000000..86afb1d9 --- /dev/null +++ b/src/link/lexer.l @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2017 Antonio Nino Diaz + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +%option noinput +%option nounput +%option noyywrap + +%{ +#include + +#include "extern/err.h" + +#include "parser.h" +%} + +%% + +\"([^\\\"]|\\.)*\" { + if (strlen(yytext) > sizeof(yylval.s) - 1) + errx(1, "String is too long: \"%s\"\n.", yytext); + if (strlen(yytext) < 3) /* 2 quotes + 1 character */ + errx(1, "String \"%s\" is invalid\n.", yytext); + + yytext++; /* ignore first quote */ + strcpy(yylval.s, yytext); + yylval.s[strlen(yylval.s)-1] = '\0'; /* remove end quote */ + + return STRING; + } + +\$[a-fA-F0-9]+ { + yytext++; /* Skip prefix */ + yylval.i = strtol(yytext, NULL, 16); + return INTEGER; + } +[0-9]+ { + yylval.i = strtol(yytext, NULL, 10); + return INTEGER; + } + +(?i:ROM0) { strcpy(yylval.s, "ROM0"); return SECTION_NONBANKED; } +(?i:ROMX) { strcpy(yylval.s, "ROMX"); return SECTION_BANKED; } +(?i:VRAM) { strcpy(yylval.s, "VRAM"); return SECTION_BANKED; } +(?i:WRAM0) { strcpy(yylval.s, "WRAM0"); return SECTION_NONBANKED; } +(?i:WRAMX) { strcpy(yylval.s, "WRAMX"); return SECTION_BANKED; } +(?i:SRAM) { strcpy(yylval.s, "SRAM"); return SECTION_BANKED; } +(?i:OAM) { strcpy(yylval.s, "OAM"); return SECTION_NONBANKED; } +(?i:HRAM) { strcpy(yylval.s, "HRAM"); return SECTION_NONBANKED; } + +(?i:ALIGN) { return COMMAND_ALIGN; } +(?i:ORG) { return COMMAND_ORG; } + +"\n" { return NEWLINE; } + +;.* { /* Ignore comments. A dot doesn't match newline. */ } + +[[:space:]] { /* Ignore whitespace. */ } + +. { errx(1, "Invalid character [%s]\n.", yytext); } + +%% + diff --git a/src/link/parser.y b/src/link/parser.y new file mode 100644 index 00000000..560d607e --- /dev/null +++ b/src/link/parser.y @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2017 Antonio Nino Diaz + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +%{ +#include + +#include "extern/err.h" +#include "link/script.h" + +int yylex(); +void yyerror(char *); + +static int nline = 1; +%} + +%union { int i; char s[512]; } + +%token INTEGER +%token STRING + +%token SECTION_NONBANKED +%token SECTION_BANKED + +%token COMMAND_ALIGN +%token COMMAND_ORG + +%token NEWLINE + +%start lines + +%% + +lines: + /* empty */ + | lines line NEWLINE + ; + +line: + /* empty */ { nline++; } + | statement { nline++; } + ; + +statement: + /* Statements to set the current section */ + SECTION_NONBANKED { + script_SetCurrentSectionType($1, 0); + } + | SECTION_NONBANKED INTEGER { + errx(1, "%d:Trying to assign a bank to a non-banked section.\n", nline); + } + + | SECTION_BANKED { + errx(1, "%d:Banked section without assigned bank.\n", nline); + } + | SECTION_BANKED INTEGER { + script_SetCurrentSectionType($1, $2); + } + + /* Commands to adjust the address inside the current section */ + | COMMAND_ALIGN INTEGER { + script_SetAlignment($2); + } + | COMMAND_ALIGN { + errx(1, "%d:ALIGN keyword needs an argument.\n", nline); + } + | COMMAND_ORG INTEGER { + script_SetAddress($2); + } + | COMMAND_ORG { + errx(1, "%d:ORG keyword needs an argument.\n", nline); + } + + /* Section name */ + | STRING { + script_OutputSection($1); + } + + /* End */ + ; + +%% + +extern int yylex(); +extern int yyparse(); + +extern FILE *yyin; + +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); +} + diff --git a/src/link/script.c b/src/link/script.c new file mode 100644 index 00000000..32d6da4f --- /dev/null +++ b/src/link/script.c @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2017 Antonio Nino Diaz + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "extern/err.h" +#include "link/assign.h" +#include "link/mylink.h" + +static struct { + unsigned int address; /* current address to write sections to */ + unsigned int top_address; /* not inclusive */ + enum eSectionType type; +} bank[MAXBANKS]; + +static int current_bank = -1; /* Bank as seen by the bank array */ +static int current_real_bank = -1; /* bank as seen by the GB */ + +void script_InitSections(void) +{ + int i; + for (i = 0; i < MAXBANKS; i++) { + if (i == BANK_ROM0) { + /* ROM0 bank */ + bank[i].address = 0x0000; + if (options & OPT_SMALL) { + bank[i].top_address = 0x8000; + } else { + bank[i].top_address = 0x4000; + } + bank[i].type = SECT_ROM0; + } else if (i >= BANK_ROMX && i < BANK_ROMX + BANK_COUNT_ROMX) { + /* Swappable ROM bank */ + bank[i].address = 0x4000; + /* + * Now, this shouldn't really be necessary... but for + * good measure we'll do it anyway. + */ + if (options & OPT_SMALL) { + bank[i].top_address = 0x4000; + } else { + bank[i].top_address = 0x8000; + } + bank[i].type = SECT_ROMX; + } else if (i == BANK_WRAM0) { + /* WRAM */ + bank[i].address = 0xC000; + if (options & OPT_CONTWRAM) { + bank[i].top_address = 0xE000; + } else { + bank[i].top_address = 0xD000; + } + bank[i].type = SECT_WRAM0; + } else if (i >= BANK_SRAM && i < BANK_SRAM + BANK_COUNT_SRAM) { + /* Swappable SRAM bank */ + bank[i].address = 0xA000; + bank[i].top_address = 0xC000; + bank[i].type = SECT_SRAM; + } else if (i >= BANK_WRAMX && i < BANK_WRAMX + BANK_COUNT_WRAMX) { + /* Swappable WRAM bank */ + bank[i].address = 0xD000; + bank[i].top_address = 0xE000; + bank[i].type = SECT_WRAMX; + } else if (i >= BANK_VRAM && i < BANK_VRAM + BANK_COUNT_VRAM) { + /* Swappable VRAM bank */ + bank[i].address = 0x8000; + bank[i].top_address = 0xA000; + bank[i].type = SECT_VRAM; + } else if (i == BANK_OAM) { + /* OAM */ + bank[i].address = 0xFE00; + bank[i].top_address = 0xFEA0; + bank[i].type = SECT_OAM; + } else if (i == BANK_HRAM) { + /* HRAM */ + bank[i].address = 0xFF80; + bank[i].top_address = 0xFFFF; + bank[i].type = SECT_HRAM; + } else { + errx(1, "(INTERNAL) Unknown bank type!"); + } + } +} + +void script_SetCurrentSectionType(const char *type, unsigned int bank) +{ + if (strcmp(type, "ROM0") == 0) { + if (bank != 0) + errx(1, "(Internal) Trying to assign a bank number to ROM0.\n"); + current_bank = BANK_ROM0; + current_real_bank = 0; + return; + } else if (strcmp(type, "ROMX") == 0) { + if (bank == 0) + errx(1, "ROMX index can't be 0.\n"); + if (bank > BANK_COUNT_ROMX) + errx(1, "ROMX index too big (%d > %d).\n", bank, BANK_COUNT_ROMX); + current_bank = BANK_ROMX + bank - 1; + current_real_bank = bank; + return; + } else if (strcmp(type, "VRAM") == 0) { + if (bank >= BANK_COUNT_VRAM) + errx(1, "VRAM index too big (%d >= %d).\n", bank, BANK_COUNT_VRAM); + current_bank = BANK_VRAM + bank; + current_real_bank = bank; + return; + } else if (strcmp(type, "WRAM0") == 0) { + if (bank != 0) + errx(1, "(Internal) Trying to assign a bank number to WRAM0.\n"); + current_bank = BANK_WRAM0; + current_real_bank = 0; + return; + } else if (strcmp(type, "WRAMX") == 0) { + if (bank == 0) + errx(1, "WRAMX index can't be 0.\n"); + if (bank > BANK_COUNT_WRAMX) + errx(1, "WRAMX index too big (%d > %d).\n", bank, BANK_COUNT_WRAMX); + current_bank = BANK_WRAMX + bank - 1; + current_real_bank = bank - 1; + return; + } else if (strcmp(type, "SRAM") == 0) { + if (bank >= BANK_COUNT_SRAM) + errx(1, "SRAM index too big (%d >= %d).\n", bank, BANK_COUNT_SRAM); + current_bank = BANK_SRAM + bank; + current_real_bank = bank; + return; + } else if (strcmp(type, "OAM") == 0) { + if (bank != 0) + errx(1, "(Internal) Trying to assign a bank number to OAM.\n"); + current_bank = BANK_OAM; + current_real_bank = 0; + return; + } else if (strcmp(type, "HRAM") == 0) { + if (bank != 0) + errx(1, "(Internal) Trying to assign a bank number to HRAM.\n"); + current_bank = BANK_HRAM; + current_real_bank = 0; + return; + } + + errx(1, "(Internal) Unknown section type \"%s\".\n", type); +} + +void script_SetAddress(unsigned int addr) +{ + if (current_bank == -1) { + errx(1, "Trying to set an address without assigned bank\n"); + } + + /* Make sure that we don't go back. */ + if (bank[current_bank].address > addr) { + errx(1, "Trying to go to a previous address (0x%04X to 0x%04X)\n", + bank[current_bank].address, addr); + } + + bank[current_bank].address = addr; + + /* Make sure we don't overflow */ + if (bank[current_bank].address >= bank[current_bank].top_address) { + errx(1, "Bank overflowed (0x%04X >= 0x%04X)\n", + bank[current_bank].address, bank[current_bank].top_address); + } +} + +void script_SetAlignment(unsigned int alignment) +{ + if (current_bank == -1) { + errx(1, "Trying to set an alignment without assigned bank\n"); + } + + if (alignment > 15) { + errx(1, "Trying to set an alignment too big: %d\n", alignment); + } + + unsigned int size = 1 << alignment; + unsigned int mask = size - 1; + + if (bank[current_bank].address & mask) { + bank[current_bank].address &= ~mask; + bank[current_bank].address += size; + } + + /* Make sure we don't overflow */ + if (bank[current_bank].address >= bank[current_bank].top_address) { + errx(1, "Bank overflowed (0x%04X >= 0x%04X)\n", + bank[current_bank].address, bank[current_bank].top_address); + } +} + +void script_OutputSection(const char *section_name) +{ + if (current_bank == -1) { + errx(1, "Trying to place section \"%s\" without assigned bank\n", section_name); + } + + if (!IsSectionSameTypeBankAndFloating(section_name, bank[current_bank].type, + current_real_bank)) { + errx(1, "Different attributes for \"%s\" in source and linkerscript\n", + section_name); + } + + /* Move section to its place. */ + bank[current_bank].address += + AssignSectionAddressByName(section_name, bank[current_bank].address); +} + From d1ed4fbdedb5afef82e0711c0ee686a4dc83044c Mon Sep 17 00:00:00 2001 From: AntonioND Date: Mon, 20 Mar 2017 23:36:14 +0000 Subject: [PATCH 2/4] Use linkerscript parser in rgblink Signed-off-by: AntonioND --- include/link/assign.h | 3 +++ src/link/assign.c | 23 ++++++++++++++++++++--- src/link/main.c | 13 ++++++++----- 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/include/link/assign.h b/include/link/assign.h index 754e0906..1dab916a 100644 --- a/include/link/assign.h +++ b/include/link/assign.h @@ -35,6 +35,9 @@ extern void CreateSymbolTable(void); extern SLONG MaxBankUsed; extern SLONG MaxAvail[MAXBANKS]; +void +SetLinkerscriptName(char *tzLinkerscriptFile); + int IsSectionSameTypeBankAndFloating(const char *name, enum eSectionType type, int bank); diff --git a/src/link/assign.c b/src/link/assign.c index 0c7a0c4b..00829b9e 100644 --- a/src/link/assign.c +++ b/src/link/assign.c @@ -4,10 +4,11 @@ #include #include "extern/err.h" +#include "link/assign.h" #include "link/mylink.h" #include "link/main.h" +#include "link/script.h" #include "link/symbol.h" -#include "link/assign.h" struct sFreeArea { SLONG nOrg; @@ -338,6 +339,14 @@ AssignFloatingBankSections(enum eSectionType type) } } +char *tzLinkerscriptName = NULL; + +void +SetLinkerscriptName(char *tzLinkerscriptFile) +{ + tzLinkerscriptName = tzLinkerscriptFile; +} + void AssignSections(void) { @@ -415,8 +424,16 @@ AssignSections(void) } /* - * First, let's assign all the fixed sections... - * And all because of that Jens Restemeier character ;) + * First, let's parse the linkerscript. + * + */ + + if (tzLinkerscriptName) { + script_Parse(tzLinkerscriptName); + } + + /* + * Second, let's assign all the fixed sections... * */ diff --git a/src/link/main.c b/src/link/main.c index 9c8c01ee..78c7dfb6 100644 --- a/src/link/main.c +++ b/src/link/main.c @@ -31,12 +31,12 @@ char *progname; * */ -static void +static void usage(void) { printf( -"usage: rgblink [-tw] [-m mapfile] [-n symfile] [-O overlay] [-o outfile] \n" -" [-p pad_value] [-s symbol] file [...]\n"); +"usage: rgblink [-tw] [-l linkerscript] [-m mapfile] [-n symfile] [-O overlay]\n" +" [-o outfile] [-p pad_value] [-s symbol] file [...]\n"); exit(1); } @@ -45,7 +45,7 @@ usage(void) * */ -int +int main(int argc, char *argv[]) { int ch; @@ -56,8 +56,11 @@ main(int argc, char *argv[]) progname = argv[0]; - while ((ch = getopt(argc, argv, "m:n:o:O:p:s:tw")) != -1) { + while ((ch = getopt(argc, argv, "l:m:n:o:O:p:s:tw")) != -1) { switch (ch) { + case 'l': + SetLinkerscriptName(optarg); + break; case 'm': SetMapfileName(optarg); break; From 5947ca10dca7d2aedd1bec76463e2c3e679f7888 Mon Sep 17 00:00:00 2001 From: AntonioND Date: Thu, 23 Mar 2017 21:00:20 +0000 Subject: [PATCH 3/4] Document linkerscript format in manpage Signed-off-by: AntonioND --- Makefile | 1 + src/link/rgblink.1 | 15 ++++++++-- src/link/rgblink.5 | 68 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 src/link/rgblink.5 diff --git a/Makefile b/Makefile index dbbd7e47..2d8f8043 100644 --- a/Makefile +++ b/Makefile @@ -82,6 +82,7 @@ install: all $Qinstall -m ${MANMODE} src/asm/rgbasm.1 ${MANPREFIX}/man1/rgbasm.1 $Qinstall -m ${MANMODE} src/fix/rgbfix.1 ${MANPREFIX}/man1/rgbfix.1 $Qinstall -m ${MANMODE} src/link/rgblink.1 ${MANPREFIX}/man1/rgblink.1 + $Qinstall -m ${MANMODE} src/link/rgblink.5 ${MANPREFIX}/man1/rgblink.5 $Qinstall -m ${MANMODE} src/gfx/rgbgfx.1 ${MANPREFIX}/man1/rgbgfx.1 rgbasm: ${rgbasm_obj} diff --git a/src/link/rgblink.1 b/src/link/rgblink.1 index 1ff59477..227e2818 100644 --- a/src/link/rgblink.1 +++ b/src/link/rgblink.1 @@ -1,4 +1,4 @@ -.Dd February 26, 2015 +.Dd March 27, 2017 .Dt RGBLINK 1 .Os RGBDS Manual .Sh NAME @@ -14,6 +14,7 @@ .Op Fl o Ar outfile .Op Fl p Ar pad_value .Op Fl s Ar symbol +.Op Fl l Ar linkerscript .Ar .Sh DESCRIPTION The @@ -54,6 +55,14 @@ Write a tiny ROM file. This forces all ROMX sections to be of type ROM0, and increases the ROM0 section size from 16KiB to 32KiB. +.It Fl l Ar linkerscript +Specify a linkerscript file that tells the linker how sections must be placed in +the ROM. +This file has priority over the attributes assigned in the source code, but they +have to be consistent. +See +.Xr rgblink 5 +for more information about its format. .El .Sh EXAMPLES All you need for a basic ROM is an object file, which can be made into a ROM @@ -70,9 +79,11 @@ to fix these so that the program will actually run in a Game Boy: .D1 $ rgbfix -v bar.gb .Sh SEE ALSO .Xr rgbasm 1 , +.Xr rgblink 5 , .Xr rgbfix 1 , .Xr rgbds 7 .Sh HISTORY .Nm was originally written by Carsten S\(/orensen as part of the ASMotor package, -and was later packaged in RGBDS by Justin Lloyd. +and was later packaged in RGBDS by Justin Lloyd. It is now maintained by a +number of contributors at https://github.com/rednex/rgbds. diff --git a/src/link/rgblink.5 b/src/link/rgblink.5 new file mode 100644 index 00000000..3d042159 --- /dev/null +++ b/src/link/rgblink.5 @@ -0,0 +1,68 @@ +.Dd March 27, 2017 +.Dt RGBLINK 5 +.Os RGBDS Manual +.Sh NAME +.Nm rgblink +.Nd linkerscript file format +.Sh DESCRIPTION +The linkerscript is an external file that allows the user to specify the +order of sections without the need for doing so before assembling each object +file. +.Pp +The placement of sections specified in the linkerscript is done before the +sections whose placement is defined in the source code. +.Pp +A linkerscript consists on a series of banks followed by a list of sections +and, optionally, commands. +They can be lowercase or uppercase, it is ignored. +Any line can contain a comment starting with +.Ql \&; +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" + + WRAMX 2 + "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. +.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: +.Bl -bullet +.It +ORG 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). +.El +.Pp +Note: The bank, alignment, address and type of sections can be specified both +in the source code and in the linkerscript. +For a section to be able to be placed with the linkerscript the bank must be +left unassigned in the source code or be the same as the one specified in the +linkerscript. The address and alignment musn't be set. +.Sh SEE ALSO +.Xr rgbasm 1 , +.Xr rgblink 1 , +.Xr rgbfix 1 , +.Xr rgbds 7 +.Sh HISTORY +.Nm +was originally written by Carsten S\(/orensen as part of the ASMotor package, +and was later packaged in RGBDS by Justin Lloyd. It is now maintained by a +number of contributors at https://github.com/rednex/rgbds. From 64dbcc09123d55fcb880eb50edec75290637d571 Mon Sep 17 00:00:00 2001 From: AntonioND Date: Thu, 23 Mar 2017 00:50:40 +0000 Subject: [PATCH 4/4] Update README.md Inform about the actual dependencies. Signed-off-by: AntonioND --- README.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f7bf3597..9c7037e4 100644 --- a/README.md +++ b/README.md @@ -14,14 +14,18 @@ other UNIX tools. ## Installing RGBDS (UNIX) -RGBDS requires libpng and pkg-config to be installed. +RGBDS requires yacc, flex, libpng and pkg-config to be installed. On Mac OS X, install them with [Homebrew](http://brew.sh/). On other Unixes, -use the built-in package manager. +use the built-in package manager. For example, on Debian or Ubuntu: -You can test if they're installed by running `pkg-config --cflags libpng`: -if the output is a path, then you're good, and if it outputs an error then -you need to install them via a package manager. +```sh +sudo apt-get install byacc flex pkg-config libpng-dev +``` + +You can test if libpng and pkg-config are installed by running +`pkg-config --cflags libpng`: if the output is a path, then you're good, and if +it outputs an error then you need to install them via a package manager. To build the programs on a UNIX or UNIX-like system, just run in your terminal: