2e2bf962db
partial link stage. * relax.c : added * config.h: if GNU960 defined, then default emulation mode is GLD960 * ldexp.h, ldexp.c: map to file hooks * ldlang.c: map to file hooks * ldgram.y: added -Map -relax * ldlex.l: added -relax, -Map * ldmain.c: open map file * ldmisc.c: support for map file * ldwrite.c: new relax magic
539 lines
10 KiB
Plaintext
539 lines
10 KiB
Plaintext
%{
|
|
/* Copyright (C) 1991 Free Software Foundation, Inc.
|
|
|
|
This file is part of GLD, the Gnu Linker.
|
|
|
|
GLD is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2, or (at your option)
|
|
any later version.
|
|
|
|
GLD is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with GLD; see the file COPYING. If not, write to
|
|
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|
|
|
/*
|
|
* $Id$
|
|
|
|
*
|
|
*/
|
|
|
|
|
|
|
|
/*SUPPRESS 529*/
|
|
/*SUPPRESS 26*/
|
|
/*SUPPRESS 29*/
|
|
/*#define LEXDEBUG 0*/
|
|
#include "bfd.h"
|
|
#include "sysdep.h"
|
|
|
|
#include <ctype.h>
|
|
#include "ldlex.h"
|
|
|
|
#include "ld.h"
|
|
#include "ldexp.h"
|
|
#include "ldgram.h"
|
|
#include "ldmisc.h"
|
|
|
|
#undef input
|
|
#undef unput
|
|
#define input lex_input
|
|
#define unput lex_unput
|
|
|
|
int debug;
|
|
|
|
|
|
static boolean ldgram_in_defsym;
|
|
static boolean ldgram_had_equals;
|
|
extern boolean ldgram_in_script;
|
|
static char *command_line;
|
|
|
|
extern int fgetc();
|
|
extern int yyparse();
|
|
|
|
typedef struct {
|
|
char *name;
|
|
int value;
|
|
} keyword_type;
|
|
#define RTOKEN(x) { yylval.token = x; return x; }
|
|
keyword_type keywords[] =
|
|
{
|
|
"/", '/',
|
|
"MEMORY",MEMORY,
|
|
"ORIGIN",ORIGIN,
|
|
"BLOCK",BLOCK,
|
|
"LENGTH",LENGTH,
|
|
"ALIGN",ALIGN_K,
|
|
"ADDR",ADDR,
|
|
"ENTRY",ENTRY,
|
|
"NEXT",NEXT,
|
|
"sizeof_headers",SIZEOF_HEADERS,
|
|
"SIZEOF_HEADERS",SIZEOF_HEADERS,
|
|
"MAP",MAP,
|
|
"SIZEOF",SIZEOF,
|
|
"TARGET",TARGET_K,
|
|
"SEARCH_DIR",SEARCH_DIR,
|
|
"OUTPUT",OUTPUT,
|
|
"INPUT",INPUT,
|
|
"DEFINED",DEFINED,
|
|
"CREATE_OBJECT_SYMBOLS",CREATE_OBJECT_SYMBOLS,
|
|
"CONSTRUCTORS", CONSTRUCTORS,
|
|
"FORCE_COMMON_ALLOCATION",FORCE_COMMON_ALLOCATION,
|
|
"SECTIONS",SECTIONS,
|
|
"FILL",FILL,
|
|
"STARTUP",STARTUP,
|
|
"OUTPUT_FORMAT",OUTPUT_FORMAT,
|
|
"OUTPUT_ARCH", OUTPUT_ARCH,
|
|
"HLL",HLL,
|
|
"SYSLIB",SYSLIB,
|
|
"FLOAT",FLOAT,
|
|
"LONG", LONG,
|
|
"SHORT", SHORT,
|
|
"BYTE", BYTE,
|
|
"NOFLOAT",NOFLOAT,
|
|
|
|
"NOLOAD",NOLOAD,
|
|
"DSECT",DSECT,
|
|
"COPY",COPY,
|
|
"INFO",INFO,
|
|
"OVERLAY",OVERLAY,
|
|
|
|
"o",ORIGIN,
|
|
"org",ORIGIN,
|
|
"l", LENGTH,
|
|
"len", LENGTH,
|
|
0,0};
|
|
unsigned int lineno;
|
|
extern boolean hex_mode;
|
|
FILE *ldlex_input_stack;
|
|
static unsigned int have_pushback;
|
|
|
|
#define NPUSHBACK 10
|
|
int pushback[NPUSHBACK];
|
|
int thischar;
|
|
extern char *ldfile_input_filename;
|
|
int donehash = 0;
|
|
int
|
|
lex_input()
|
|
{
|
|
if (have_pushback > 0)
|
|
{
|
|
have_pushback --;
|
|
return thischar = pushback[have_pushback];
|
|
}
|
|
if (ldlex_input_stack) {
|
|
thischar = fgetc(ldlex_input_stack);
|
|
|
|
if (thischar == EOF) {
|
|
fclose(ldlex_input_stack);
|
|
ldlex_input_stack = (FILE *)NULL;
|
|
ldfile_input_filename = (char *)NULL;
|
|
/* First char after script eof is a @ so that we can tell the grammer
|
|
that we've left */
|
|
thischar = '@';
|
|
|
|
}
|
|
}
|
|
else if (command_line && *command_line) {
|
|
thischar = *(command_line++);
|
|
}
|
|
else {
|
|
thischar = 0;
|
|
}
|
|
if(thischar == '\t') thischar = ' ';
|
|
if (thischar == '\n') { thischar = ' '; lineno++; }
|
|
return thischar ;
|
|
}
|
|
|
|
void
|
|
lex_unput(c)
|
|
int c;
|
|
{
|
|
if (have_pushback > NPUSHBACK) {
|
|
info("%F%P Too many pushbacks\n");
|
|
}
|
|
|
|
pushback[have_pushback] = c;
|
|
have_pushback ++;
|
|
}
|
|
|
|
|
|
int
|
|
yywrap()
|
|
{ return 1; }
|
|
/*VARARGS*/
|
|
|
|
void
|
|
allprint(x)
|
|
int x;
|
|
{
|
|
fprintf(yyout,"%d",x);
|
|
}
|
|
|
|
void
|
|
sprint(x)
|
|
char *x;
|
|
{
|
|
fprintf(yyout,"%s",x);
|
|
}
|
|
|
|
int thischar;
|
|
|
|
void parse_line(arg)
|
|
char *arg;
|
|
{
|
|
command_line = arg;
|
|
have_pushback = 0;
|
|
yyparse();
|
|
}
|
|
|
|
|
|
|
|
void
|
|
parse_args(ac, av)
|
|
int ac;
|
|
char **av;
|
|
{
|
|
char *p;
|
|
int i;
|
|
size_t size = 0;
|
|
char *dst;
|
|
debug = 1;
|
|
for (i= 1; i < ac; i++) {
|
|
size += strlen(av[i]) + 2;
|
|
}
|
|
dst = p = (char *)ldmalloc(size + 2);
|
|
/* Put a space arount each option */
|
|
|
|
|
|
for (i =1; i < ac; i++) {
|
|
|
|
unsigned int s = strlen(av[i]);
|
|
*dst++ = ' ';
|
|
memcpy(dst, av[i], s);
|
|
dst[s] = ' ';
|
|
dst += s + 1;
|
|
}
|
|
*dst = 0;
|
|
parse_line(p);
|
|
|
|
free(p);
|
|
|
|
|
|
}
|
|
|
|
static long
|
|
DEFUN(number,(default_if_zero,base),
|
|
int default_if_zero AND
|
|
int base)
|
|
{
|
|
unsigned long l = 0;
|
|
int ch = yytext[0];
|
|
if (ch == 0) {
|
|
base = default_if_zero;
|
|
}
|
|
while (1) {
|
|
switch (ch) {
|
|
case 'x':
|
|
base = 16;
|
|
break;
|
|
case 'k':
|
|
case 'K':
|
|
l =l * 1024;
|
|
break;
|
|
case 'm':
|
|
case 'M':
|
|
l =l * 1024 * 1024;
|
|
break;
|
|
case '0': case '1': case '2': case '3': case '4':
|
|
case '5': case '6': case '7': case '8': case '9':
|
|
l = l * base + ch - '0';
|
|
break;
|
|
case 'a': case 'b': case 'c' : case 'd' : case 'e': case 'f':
|
|
l =l *base + ch - 'a' + 10;
|
|
break;
|
|
case 'A': case 'B': case 'C' : case 'D' : case 'E': case 'F':
|
|
l =l *base + ch - 'A' + 10;
|
|
break;
|
|
default:
|
|
unput(ch);
|
|
yylval.integer = l;
|
|
return INT;
|
|
}
|
|
ch = input();
|
|
}
|
|
}
|
|
%}
|
|
|
|
%a 4000
|
|
%o 5000
|
|
FILENAMECHAR [a-zA-Z0-9\/\.\-\_\+\=]
|
|
FILENAME {FILENAMECHAR}+
|
|
WHITE [ \t]+
|
|
|
|
%%
|
|
|
|
"@" { return '}'; }
|
|
"\ -defsym\ " { ldgram_in_defsym = true; return OPTION_defsym; }
|
|
"\ -noinhibit_exec\ " { return OPTION_noinhibit_exec; }
|
|
"\ -sort_common\ " { return OPTION_sort_common;}
|
|
"\ -format\ " { return OPTION_format; }
|
|
"\ -n\ " { return OPTION_n; }
|
|
"\ -N\ " { return OPTION_N; }
|
|
"\ -r\ " { return OPTION_r; }
|
|
"\ -relax\ " { return OPTION_relax; }
|
|
"\ -i\ " { return OPTION_r; }
|
|
"\ -Ur\ " { return OPTION_Ur; }
|
|
"\ -o\ " { return OPTION_o; }
|
|
"\ -g\ " { return OPTION_g; }
|
|
"\ -e\ " { return OPTION_e; }
|
|
"\ -b\ " { return OPTION_b; }
|
|
"\ -dc\ " { return OPTION_dc; }
|
|
"\ -dp\ " { return OPTION_dp; }
|
|
"\ -d\ " { return OPTION_d; }
|
|
"\ -v\ " { return OPTION_v; }
|
|
"\ -V\ " { return OPTION_V; }
|
|
"\ -M\ " { return OPTION_M; }
|
|
"\ -Map\ " { return OPTION_Map;}
|
|
"\ -t\ " { return OPTION_t; }
|
|
"\ -X\ " { return OPTION_X; }
|
|
"\ -x\ " { return OPTION_x; }
|
|
"\ -c\ " { return OPTION_c; }
|
|
"\ -R\ " { return OPTION_R; }
|
|
"\ -u\ " { return OPTION_u; }
|
|
"\ -s\ " { return OPTION_s; }
|
|
"\ -S\ " { return OPTION_S; }
|
|
"\ -Bstatic" { return OPTION_Bstatic; }
|
|
"\ -B{FILENAME}\ " { /* Ignored */ }
|
|
"\ -l"{FILENAME} {
|
|
yylval.name = buystring(yytext+3);
|
|
return OPTION_l;
|
|
}
|
|
|
|
"\ -L"{FILENAME} {
|
|
yylval.name = buystring(yytext+3);
|
|
return OPTION_L;
|
|
}
|
|
"\ -Ttext\ " {
|
|
yylval.name = ".text";
|
|
return OPTION_Texp;
|
|
}
|
|
"\ -Tdata\ " {
|
|
yylval.name = ".data";
|
|
return OPTION_Texp;
|
|
}
|
|
"\ -Tbss\ " {
|
|
yylval.name = ".bss";
|
|
return OPTION_Texp;
|
|
}
|
|
"\ -O"{FILENAME} {
|
|
yylval.name = buystring(yytext+3);
|
|
return OPTION_Texp;
|
|
}
|
|
|
|
"\ -T"{FILENAME} {
|
|
yylval.name = buystring(yytext+3);
|
|
return OPTION_Tfile;
|
|
}
|
|
"\ -T\ " {
|
|
return OPTION_T;
|
|
}
|
|
|
|
"\ -F"{FILENAME} {
|
|
return OPTION_F;
|
|
}
|
|
"\ -F\ " {
|
|
return OPTION_F;
|
|
}
|
|
|
|
"\ -A"{FILENAME} {
|
|
yylval.name = buystring(yytext+3);
|
|
return OPTION_Aarch;
|
|
}
|
|
|
|
" " {
|
|
if (ldgram_had_equals == true) {
|
|
ldgram_in_defsym = false;
|
|
ldgram_had_equals = false;
|
|
}
|
|
}
|
|
"<<=" { RTOKEN(LSHIFTEQ);}
|
|
">>=" { RTOKEN(RSHIFTEQ);}
|
|
"||" { RTOKEN(OROR);}
|
|
"==" { RTOKEN(EQ);}
|
|
"!=" { RTOKEN(NE);}
|
|
">=" { RTOKEN(GE);}
|
|
"<=" { RTOKEN(LE);}
|
|
"<<" { RTOKEN(LSHIFT);}
|
|
">>" { RTOKEN(RSHIFT);}
|
|
"+=" { RTOKEN(PLUSEQ);}
|
|
"-=" { RTOKEN(MINUSEQ);}
|
|
"*=" { RTOKEN(MULTEQ);}
|
|
"/=" { RTOKEN(DIVEQ);}
|
|
"&=" { RTOKEN(ANDEQ);}
|
|
"|=" { RTOKEN(OREQ);}
|
|
"&&" { RTOKEN(ANDAND);}
|
|
">" { RTOKEN('>');}
|
|
"," { RTOKEN(',');}
|
|
"&" { RTOKEN('&');}
|
|
"|" { RTOKEN('|');}
|
|
"~" { RTOKEN('~');}
|
|
"!" { RTOKEN('!');}
|
|
"?" { RTOKEN('?');}
|
|
"*" { RTOKEN('*');}
|
|
"%" { RTOKEN('%');}
|
|
"<" { RTOKEN('<');}
|
|
">" { RTOKEN('>');}
|
|
"}" { RTOKEN('}') ; }
|
|
"{" { RTOKEN('{'); }
|
|
")" { RTOKEN(')');}
|
|
"(" { RTOKEN('(');}
|
|
"]" { RTOKEN(']');}
|
|
"[" { RTOKEN('[');}
|
|
":" { RTOKEN(':'); }
|
|
";" { RTOKEN(';');}
|
|
"-" { RTOKEN('-');}
|
|
|
|
|
|
|
|
"/*" {
|
|
while (1) {
|
|
int ch;
|
|
ch = input();
|
|
while (ch != '*') {
|
|
ch = input();
|
|
}
|
|
|
|
|
|
|
|
if (input() == '/') {
|
|
break;
|
|
}
|
|
unput(yytext[yyleng-1]);
|
|
}
|
|
}
|
|
|
|
"\""[^\"]*"\"" {
|
|
|
|
yylval.name = buystring(yytext+1);
|
|
yylval.name[yyleng-2] = 0; /* Fry final quote */
|
|
return NAME;
|
|
}
|
|
|
|
{FILENAMECHAR} {
|
|
|
|
boolean loop = false;
|
|
int ch;
|
|
keyword_type *k;
|
|
|
|
/* If we're in hex mode (only after a -T) then all we can see are numbers
|
|
hex digit we see will be a number. */
|
|
|
|
if (hex_mode) {
|
|
return number(16, 16);
|
|
}
|
|
|
|
/* If we're in a defsym then all things starting with a digit are in
|
|
hex */
|
|
|
|
if (isdigit(yytext[0]) && ldgram_in_defsym) {
|
|
return number(16,16);
|
|
}
|
|
|
|
|
|
/* Otherwise if we're in a script we will parse the numbers
|
|
normally */
|
|
|
|
if (ldgram_in_script == true && isdigit(yytext[0])) {
|
|
return number(8,10);
|
|
}
|
|
|
|
/* Anywhere not in a script or defsym, an opertor is part of a
|
|
filename, except / and, which is an operator when on its own */
|
|
if (ldgram_in_script == true|| ldgram_in_defsym == true) {
|
|
|
|
switch (yytext[0]) {
|
|
case '*': RTOKEN('*');
|
|
|
|
case '=': {
|
|
ldgram_had_equals = true;
|
|
RTOKEN('=');
|
|
}
|
|
break;
|
|
case '/': {
|
|
if (ldgram_in_defsym) RTOKEN('/');
|
|
}
|
|
break;
|
|
case '+': RTOKEN('+');
|
|
case '-': RTOKEN('-');
|
|
case '!': RTOKEN('!');
|
|
case '~': RTOKEN('~');
|
|
}
|
|
}
|
|
|
|
|
|
/* Otherwise this must be a file or a symbol name, and it will continue to be a
|
|
filename until we get to something strange. In scripts operator looking
|
|
things are taken to be operators, except /, which will be left
|
|
*/
|
|
ch = input();
|
|
while (true)
|
|
{
|
|
if (ldgram_in_defsym == true) {
|
|
switch (ch) {
|
|
case '*':
|
|
case '=':
|
|
case '+':
|
|
case '/':
|
|
case '-':
|
|
case '!':
|
|
case '~':
|
|
goto quit;
|
|
}
|
|
|
|
}
|
|
if(ldgram_in_script == true) {
|
|
switch (ch) {
|
|
case '*':
|
|
case '=':
|
|
case '+':
|
|
case '-':
|
|
case '!':
|
|
case '~':
|
|
goto quit;
|
|
}
|
|
}
|
|
|
|
if (isalpha(ch) || isdigit(ch) || ch == '.' || ch == '_' ||
|
|
ch == '/' || ch == '.' || ch == '+' || ch == '-' || ch =='=') {
|
|
yytext[yyleng++] = ch;
|
|
}
|
|
else
|
|
break;
|
|
ch = input();
|
|
}
|
|
quit:;
|
|
yytext[yyleng] = 0;
|
|
unput(ch);
|
|
|
|
for(k = keywords; k ->name != (char *)NULL; k++) {
|
|
if (strcmp(k->name, yytext)==0) {
|
|
yylval.token = k->value;
|
|
return k->value;
|
|
}
|
|
}
|
|
yylval.name = buystring(yytext);
|
|
return NAME;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
%%
|