diff options
Diffstat (limited to 'ld/deffilep.y')
-rw-r--r-- | ld/deffilep.y | 978 |
1 files changed, 978 insertions, 0 deletions
diff --git a/ld/deffilep.y b/ld/deffilep.y new file mode 100644 index 0000000..c0f350b --- /dev/null +++ b/ld/deffilep.y @@ -0,0 +1,978 @@ +%{ /* deffilep.y - parser for .def files */ + +/* Copyright (C) 1995, 1997, 1998 Free Software Foundation, Inc. + +This file is part of GNU Binutils. + +This program 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 of the License, or +(at your option) any later version. + +This program 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 this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <stdio.h> +#include <ctype.h> +#include "libiberty.h" +#include "bfd.h" +#include "ld.h" +#include "deffile.h" + +#define TRACE 0 + +/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc), + as well as gratuitiously global symbol names, so we can have multiple + yacc generated parsers in ld. Note that these are only the variables + produced by yacc. If other parser generators (bison, byacc, etc) produce + additional global names that conflict at link time, then those parser + generators need to be fixed instead of adding those names to this list. */ + +#define yymaxdepth def_maxdepth +#define yyparse def_parse +#define yylex def_lex +#define yyerror def_error +#define yylval def_lval +#define yychar def_char +#define yydebug def_debug +#define yypact def_pact +#define yyr1 def_r1 +#define yyr2 def_r2 +#define yydef def_def +#define yychk def_chk +#define yypgo def_pgo +#define yyact def_act +#define yyexca def_exca +#define yyerrflag def_errflag +#define yynerrs def_nerrs +#define yyps def_ps +#define yypv def_pv +#define yys def_s +#define yy_yys def_yys +#define yystate def_state +#define yytmp def_tmp +#define yyv def_v +#define yy_yyv def_yyv +#define yyval def_val +#define yylloc def_lloc +#define yyreds def_reds /* With YYDEBUG defined */ +#define yytoks def_toks /* With YYDEBUG defined */ +#define yylhs def_yylhs +#define yylen def_yylen +#define yydefred def_yydefred +#define yydgoto def_yydgoto +#define yysindex def_yysindex +#define yyrindex def_yyrindex +#define yygindex def_yygindex +#define yytable def_yytable +#define yycheck def_yycheck + +static int def_lex (); + +static void def_description PARAMS ((const char *)); +static void def_exports PARAMS ((const char *, const char *, int, int)); +static void def_heapsize PARAMS ((int, int)); +static void def_import + PARAMS ((const char *, const char *, const char *, const char *, int)); +static void def_library PARAMS ((const char *, int)); +static void def_name PARAMS ((const char *, int)); +static void def_section PARAMS ((const char *, int)); +static void def_section_alt PARAMS ((const char *, const char *)); +static void def_stacksize PARAMS ((int, int)); +static void def_version PARAMS ((int, int)); +static void def_directive PARAMS ((char *)); +static int def_parse PARAMS ((void)); +static int def_error PARAMS ((const char *)); +static int def_debug; +static int def_lex PARAMS ((void)); + +static int lex_forced_token = 0; +static const char *lex_parse_string = 0; +static const char *lex_parse_string_end = 0; + +%} + +%union { + char *id; + int number; +}; + +%token NAME, LIBRARY, DESCRIPTION, STACKSIZE, HEAPSIZE, CODE, DATA +%token SECTIONS, EXPORTS, IMPORTS, VERSIONK, BASE, CONSTANT, PRIVATE +%token READ WRITE EXECUTE SHARED NONAME DIRECTIVE +%token <id> ID +%token <number> NUMBER +%type <number> opt_base opt_ordinal +%type <number> attr attr_list opt_number exp_opt_list exp_opt +%type <id> opt_name opt_equal_name + +%% + +start: start command + | command + ; + +command: + NAME opt_name opt_base { def_name ($2, $3); } + | LIBRARY opt_name opt_base { def_library ($2, $3); } + | DESCRIPTION ID { def_description ($2);} + | STACKSIZE NUMBER opt_number { def_stacksize ($2, $3);} + | HEAPSIZE NUMBER opt_number { def_heapsize ($2, $3);} + | CODE attr_list { def_section ("CODE", $2);} + | DATA attr_list { def_section ("DATA", $2);} + | SECTIONS seclist + | EXPORTS explist + | IMPORTS implist + | VERSIONK NUMBER { def_version ($2, 0);} + | VERSIONK NUMBER '.' NUMBER { def_version ($2, $4);} + | DIRECTIVE ID { def_directive ($2);} + ; + + +explist: + /* EMPTY */ + | expline + | explist expline + ; + +expline: + ID opt_equal_name opt_ordinal exp_opt_list + { def_exports ($1, $2, $3, $4); } + ; +exp_opt_list: + exp_opt exp_opt_list { $$ = $1 | $2; } + | { $$ = 0; } + ; +exp_opt: + NONAME { $$ = 1; } + | CONSTANT { $$ = 2; } + | DATA { $$ = 4; } + | PRIVATE { $$ = 8; } + ; +implist: + implist impline + | impline + ; + +impline: + ID '=' ID '.' ID '.' ID { def_import ($1, $3, $5, $7, -1); } + | ID '=' ID '.' ID '.' NUMBER { def_import ($1, $3, $5, 0, $7); } + | ID '=' ID '.' ID { def_import ($1, $3, 0, $5, -1); } + | ID '=' ID '.' NUMBER { def_import ($1, $3, 0, 0, $5); } + | ID '.' ID '.' ID { def_import ( 0, $1, $3, $5, -1); } + | ID '.' ID { def_import ( 0, $1, 0, $3, -1); } +; + +seclist: + seclist secline + | secline + ; + +secline: + ID attr_list { def_section ($1, $2);} + | ID ID { def_section_alt ($1, $2);} + ; + +attr_list: + attr_list opt_comma attr { $$ = $1 | $3; } + | attr { $$ = $1; } + ; + +opt_comma: + ',' + | + ; +opt_number: ',' NUMBER { $$=$2;} + | { $$=-1;} + ; + +attr: + READ { $$ = 1;} + | WRITE { $$ = 2;} + | EXECUTE { $$=4;} + | SHARED { $$=8;} + ; + +opt_name: ID { $$ = $1; } + | { $$ = 0; } + ; + +opt_ordinal: + '@' NUMBER { $$ = $2;} + | { $$ = -1;} + ; + +opt_equal_name: + '=' ID { $$ = $2; } + | { $$ = 0; } + ; + +opt_base: BASE '=' NUMBER { $$ = $3;} + | { $$ = 0;} + ; + + + +%% + +/***************************************************************************** + API + *****************************************************************************/ + +static FILE *the_file; +static const char *def_filename; +static int linenumber; +static def_file *def; +static int max_exports, max_imports, max_sections; +static int saw_newline; + +struct directive + { + struct directive *next; + char *name; + int len; + }; + +static struct directive *directives = 0; + +def_file * +def_file_empty () +{ + def_file *rv = (def_file *) xmalloc (sizeof (def_file)); + memset (rv, 0, sizeof (def_file)); + max_exports = max_imports = max_sections = 0; + rv->is_dll = -1; + rv->base_address = (bfd_vma) (-1); + rv->stack_reserve = rv->stack_commit = -1; + rv->heap_reserve = rv->heap_commit = -1; + rv->version_major = rv->version_minor = -1; + return rv; +} + +def_file * +def_file_parse (filename, add_to) + const char *filename; + def_file *add_to; +{ + struct directive *d; + + the_file = fopen (filename, "r"); + def_filename = filename; + linenumber = 1; + if (!the_file) + { + perror (filename); + return 0; + } + if (add_to) + { + def = add_to; + max_exports = def->num_exports; + max_imports = def->num_imports; + max_sections = def->num_section_defs; + } + else + { + def = def_file_empty (); + } + + saw_newline = 1; + if (def_parse ()) + { + def_file_free (def); + fclose (the_file); + return 0; + } + + fclose (the_file); + + for (d = directives; d; d = d->next) + { +#if TRACE + printf ("Adding directive `%s'\n", d->name); +#endif + def_file_add_directive (def, d->name, d->len); + } + + return def; +} + +void +def_file_free (def) + def_file *def; +{ + int i; + if (!def) + return; + if (def->name) + free (def->name); + if (def->description) + free (def->description); + + if (def->section_defs) + { + for (i = 0; i < def->num_section_defs; i++) + { + if (def->section_defs[i].name) + free (def->section_defs[i].name); + if (def->section_defs[i].class) + free (def->section_defs[i].class); + } + free (def->section_defs); + } + + if (def->exports) + { + for (i = 0; i < def->num_exports; i++) + { + if (def->exports[i].internal_name + && def->exports[i].internal_name != def->exports[i].name) + free (def->exports[i].internal_name); + if (def->exports[i].name) + free (def->exports[i].name); + } + free (def->exports); + } + + if (def->imports) + { + for (i = 0; i < def->num_imports; i++) + { + if (def->imports[i].internal_name + && def->imports[i].internal_name != def->imports[i].name) + free (def->imports[i].internal_name); + if (def->imports[i].name) + free (def->imports[i].name); + if (def->imports[i].module) + free (def->imports[i].module); + } + free (def->imports); + } + + free (def); +} + +#ifdef DEF_FILE_PRINT +void +def_file_print (file, def) + FILE *file; + def_file *def; +{ + int i; + fprintf (file, ">>>> def_file at 0x%08x\n", def); + if (def->name) + fprintf (file, " name: %s\n", def->name ? def->name : "(unspecified)"); + if (def->is_dll != -1) + fprintf (file, " is dll: %s\n", def->is_dll ? "yes" : "no"); + if (def->base_address != (bfd_vma) (-1)) + fprintf (file, " base address: 0x%08x\n", def->base_address); + if (def->description) + fprintf (file, " description: `%s'\n", def->description); + if (def->stack_reserve != -1) + fprintf (file, " stack reserve: 0x%08x\n", def->stack_reserve); + if (def->stack_commit != -1) + fprintf (file, " stack commit: 0x%08x\n", def->stack_commit); + if (def->heap_reserve != -1) + fprintf (file, " heap reserve: 0x%08x\n", def->heap_reserve); + if (def->heap_commit != -1) + fprintf (file, " heap commit: 0x%08x\n", def->heap_commit); + + if (def->num_section_defs > 0) + { + fprintf (file, " section defs:\n"); + for (i = 0; i < def->num_section_defs; i++) + { + fprintf (file, " name: `%s', class: `%s', flags:", + def->section_defs[i].name, def->section_defs[i].class); + if (def->section_defs[i].flag_read) + fprintf (file, " R"); + if (def->section_defs[i].flag_write) + fprintf (file, " W"); + if (def->section_defs[i].flag_execute) + fprintf (file, " X"); + if (def->section_defs[i].flag_shared) + fprintf (file, " S"); + fprintf (file, "\n"); + } + } + + if (def->num_exports > 0) + { + fprintf (file, " exports:\n"); + for (i = 0; i < def->num_exports; i++) + { + fprintf (file, " name: `%s', int: `%s', ordinal: %d, flags:", + def->exports[i].name, def->exports[i].internal_name, + def->exports[i].ordinal); + if (def->exports[i].flag_private) + fprintf (file, " P"); + if (def->exports[i].flag_constant) + fprintf (file, " C"); + if (def->exports[i].flag_noname) + fprintf (file, " N"); + if (def->exports[i].flag_data) + fprintf (file, " D"); + fprintf (file, "\n"); + } + } + + if (def->num_imports > 0) + { + fprintf (file, " imports:\n"); + for (i = 0; i < def->num_imports; i++) + { + fprintf (file, " int: %s, from: `%s', name: `%s', ordinal: %d\n", + def->imports[i].internal_name, + def->imports[i].module, + def->imports[i].name, + def->imports[i].ordinal); + } + } + if (def->version_major != -1) + fprintf (file, " version: %d.%d\n", def->version_major, def->version_minor); + fprintf (file, "<<<< def_file at 0x%08x\n", def); +} +#endif + +def_file_export * +def_file_add_export (def, external_name, internal_name, ordinal) + def_file *def; + const char *external_name; + const char *internal_name; + int ordinal; +{ + def_file_export *e; + if (def->num_exports >= max_exports) + { + max_exports = def->num_exports + 50; + if (def->exports) + def->exports = (def_file_export *) xrealloc (def->exports, max_exports * sizeof (def_file_export)); + else + def->exports = (def_file_export *) xmalloc (max_exports * sizeof (def_file_export)); + } + e = def->exports + def->num_exports; + memset (e, 0, sizeof (def_file_export)); + if (internal_name && !external_name) + external_name = internal_name; + if (external_name && !internal_name) + internal_name = external_name; + e->name = xstrdup (external_name); + e->internal_name = xstrdup (internal_name); + e->ordinal = ordinal; + def->num_exports++; + return e; +} + +def_file_import * +def_file_add_import (def, name, module, ordinal, internal_name) + def_file *def; + const char *name; + const char *module; + int ordinal; + const char *internal_name; +{ + def_file_import *i; + if (def->num_imports >= max_imports) + { + max_imports = def->num_imports + 50; + if (def->imports) + def->imports = (def_file_import *) xrealloc (def->imports, max_imports * sizeof (def_file_import)); + else + def->imports = (def_file_import *) xmalloc (max_imports * sizeof (def_file_import)); + } + i = def->imports + def->num_imports; + memset (i, 0, sizeof (def_file_import)); + if (name) + i->name = xstrdup (name); + if (module) + i->module = xstrdup (module); + i->ordinal = ordinal; + if (internal_name) + i->internal_name = xstrdup (internal_name); + else + i->internal_name = i->name; + def->num_imports++; + return i; +} + +struct +{ + char *param; + int token; +} +diropts[] = +{ + { "-heap", HEAPSIZE }, + { "-stack", STACKSIZE }, + { "-attr", SECTIONS }, + { "-export", EXPORTS }, + { 0, 0 } +}; + +int +def_file_add_directive (my_def, param, len) + def_file *my_def; + const char *param; + int len; +{ + def_file *save_def = def; + const char *pend = param + len; + const char *tend = param; + unsigned int sh_reserve, sh_commit; + int i, j; + + def = my_def; + + while (param < pend) + { + while (param < pend && isspace (*param)) + param++; + for (tend = param + 1; + tend < pend && !(isspace (tend[-1]) && *tend == '-'); + tend++); + + for (i = 0; diropts[i].param; i++) + { + int len = strlen (diropts[i].param); + if (tend - param >= len + && strncmp (param, diropts[i].param, len) == 0 + && (param[len] == ':' || param[len] == ' ')) + { + lex_parse_string_end = tend; + lex_parse_string = param + len + 1; + lex_forced_token = diropts[i].token; + saw_newline = 0; + def_parse (); + break; + } + } + + if (!diropts[i].param) + { + /* xgettext:c-format */ + einfo (_("Warning: .drectve `%.*s' unrecognized\n"), + tend - param, param); + } + lex_parse_string = 0; + param = tend; + } + + def = save_def; +} + +/***************************************************************************** + Parser Callbacks + *****************************************************************************/ + +static void +def_name (name, base) + const char *name; + int base; +{ + if (def->name) + free (def->name); + def->name = xstrdup (name); + def->base_address = base; + def->is_dll = 0; +} + +static void +def_library (name, base) + const char *name; + int base; +{ + if (def->name) + free (def->name); + def->name = xstrdup (name); + def->base_address = base; + def->is_dll = 1; +} + +static void +def_description (text) + const char *text; +{ + int len = def->description ? strlen (def->description) : 0; + len += strlen (text) + 1; + if (def->description) + { + def->description = (char *) xrealloc (def->description, len); + strcat (def->description, text); + } + else + { + def->description = (char *) xmalloc (len); + strcpy (def->description, text); + } +} + +static void +def_stacksize (reserve, commit) + int reserve; + int commit; +{ + def->stack_reserve = reserve; + def->stack_commit = commit; +} + +static void +def_heapsize (reserve, commit) + int reserve; + int commit; +{ + def->heap_reserve = reserve; + def->heap_commit = commit; +} + +static void +def_section (name, attr) + const char *name; + int attr; +{ + def_file_section *s; + if (def->num_section_defs >= max_sections) + { + max_sections = def->num_section_defs + 50; + if (def->section_defs) + def->section_defs = (def_file_section *) xrealloc (def->section_defs, max_sections * sizeof (def_file_import)); + else + def->section_defs = (def_file_section *) xmalloc (max_sections * sizeof (def_file_import)); + } + s = def->section_defs + def->num_section_defs; + memset (s, 0, sizeof (def_file_section)); + s->name = xstrdup (name); + if (attr & 1) + s->flag_read = 1; + if (attr & 2) + s->flag_write = 1; + if (attr & 4) + s->flag_execute = 1; + if (attr & 8) + s->flag_shared = 1; + + def->num_section_defs++; +} + +static void +def_section_alt (name, attr) + const char *name; + const char *attr; +{ + int aval = 0; + for (; *attr; attr++) + { + switch (*attr) + { + case 'R': + case 'r': + aval |= 1; + break; + case 'W': + case 'w': + aval |= 2; + break; + case 'X': + case 'x': + aval |= 4; + break; + case 'S': + case 's': + aval |= 8; + break; + } + } + def_section (name, aval); +} + +static void +def_exports (external_name, internal_name, ordinal, flags) + const char *external_name; + const char *internal_name; + int ordinal; + int flags; +{ + def_file_export *dfe; + + if (!internal_name && external_name) + internal_name = external_name; +#if TRACE + printf ("def_exports, ext=%s int=%s\n", external_name, internal_name); +#endif + + dfe = def_file_add_export (def, external_name, internal_name, ordinal); + if (flags & 1) + dfe->flag_noname = 1; + if (flags & 2) + dfe->flag_constant = 1; + if (flags & 4) + dfe->flag_data = 1; + if (flags & 8) + dfe->flag_private = 1; +} + +static void +def_import (internal_name, module, dllext, name, ordinal) + const char *internal_name; + const char *module; + const char *dllext; + const char *name; + int ordinal; +{ + char *buf = 0; + + if (dllext != NULL) + { + buf = (char *) xmalloc (strlen (module) + strlen (dllext) + 2); + sprintf (buf, "%s.%s", module, dllext); + module = buf; + } + + def_file_add_import (def, name, module, ordinal, internal_name); + if (buf) + free (buf); +} + +static void +def_version (major, minor) + int major; + int minor; +{ + def->version_major = major; + def->version_minor = minor; +} + +static void +def_directive (str) + char *str; +{ + struct directive *d = (struct directive *) xmalloc (sizeof (struct directive)); + d->next = directives; + directives = d; + d->name = xstrdup (str); + d->len = strlen (str); +} + +static int +def_error (err) + const char *err; +{ + einfo ("%P: %s:%d: %s\n", def_filename, linenumber, err); + + return 0; +} + + +/***************************************************************************** + Lexical Scanner + *****************************************************************************/ + +#undef TRACE +#define TRACE 0 + +/* Never freed, but always reused as needed, so no real leak */ +static char *buffer = 0; +static int buflen = 0; +static int bufptr = 0; + +static void +put_buf (c) + char c; +{ + if (bufptr == buflen) + { + buflen += 50; /* overly reasonable, eh? */ + if (buffer) + buffer = (char *) xrealloc (buffer, buflen + 1); + else + buffer = (char *) xmalloc (buflen + 1); + } + buffer[bufptr++] = c; + buffer[bufptr] = 0; /* not optimal, but very convenient */ +} + +static struct +{ + char *name; + int token; +} +tokens[] = +{ + { "BASE", BASE }, + { "CODE", CODE }, + { "CONSTANT", CONSTANT }, + { "DATA", DATA }, + { "DESCRIPTION", DESCRIPTION }, + { "DIRECTIVE", DIRECTIVE }, + { "EXECUTE", EXECUTE }, + { "EXPORTS", EXPORTS }, + { "HEAPSIZE", HEAPSIZE }, + { "IMPORTS", IMPORTS }, + { "LIBRARY", LIBRARY }, + { "NAME", NAME }, + { "NONAME", NONAME }, + { "PRIVATE", PRIVATE }, + { "READ", READ }, + { "SECTIONS", SECTIONS }, + { "SEGMENTS", SECTIONS }, + { "SHARED", SHARED }, + { "STACKSIZE", STACKSIZE }, + { "VERSION", VERSIONK }, + { "WRITE", WRITE }, + { 0, 0 } +}; + +static int +def_getc () +{ + int rv; + if (lex_parse_string) + { + if (lex_parse_string >= lex_parse_string_end) + rv = EOF; + else + rv = *lex_parse_string++; + } + else + { + rv = fgetc (the_file); + } + if (rv == '\n') + saw_newline = 1; + return rv; +} + +static int +def_ungetc (c) + int c; +{ + if (lex_parse_string) + lex_parse_string--; + else + return ungetc (c, the_file); +} + +static int +def_lex () +{ + int c, i, q; + + if (lex_forced_token) + { + i = lex_forced_token; + lex_forced_token = 0; +#if TRACE + printf ("lex: forcing token %d\n", i); +#endif + return i; + } + + c = def_getc (); + + /* trim leading whitespace */ + while (c != EOF && (c == ' ' || c == '\t') && saw_newline) + c = def_getc (); + + if (c == EOF) + { +#if TRACE + printf ("lex: EOF\n"); +#endif + return 0; + } + + if (saw_newline && c == ';') + { + do + { + c = def_getc (); + } + while (c != EOF && c != '\n'); + if (c == '\n') + return def_lex (); + return 0; + } + /* must be something else */ + saw_newline = 0; + + if (isdigit (c)) + { + bufptr = 0; + while (c != EOF && isxdigit (c) || (c == 'x')) + { + put_buf (c); + c = def_getc (); + } + if (c != EOF) + def_ungetc (c); + yylval.number = strtoul (buffer, 0, 0); +#if TRACE + printf ("lex: `%s' returns NUMBER %d\n", buffer, yylval.number); +#endif + return NUMBER; + } + + if (isalpha (c) || strchr ("$:-_?", c)) + { + bufptr = 0; + while (c != EOF && isalnum (c) || strchr ("$:-_?/@", c)) + { + put_buf (c); + c = def_getc (); + } + if (c != EOF) + def_ungetc (c); + for (i = 0; tokens[i].name; i++) + if (strcmp (tokens[i].name, buffer) == 0) + { +#if TRACE + printf ("lex: `%s' is a string token\n", buffer); +#endif + return tokens[i].token; + } +#if TRACE + printf ("lex: `%s' returns ID\n", buffer); +#endif + yylval.id = xstrdup (buffer); + return ID; + } + + if (c == '\'' || c == '"') + { + q = c; + c = def_getc (); + bufptr = 0; + while (c != EOF && c != q) + { + put_buf (c); + c = def_getc (); + } + yylval.id = xstrdup (buffer); +#if TRACE + printf ("lex: `%s' returns ID\n", buffer); +#endif + return ID; + } + + if (c == '=' || c == '.' || c == '@' || c == ',') + { +#if TRACE + printf ("lex: `%c' returns itself\n", c); +#endif + return c; + } + + if (c == '\n') + { + linenumber++; + saw_newline = 1; + } + + /*printf ("lex: 0x%02x ignored\n", c); */ + return def_lex (); +} |