From b930d117d3929c0b5a199660f8c17c30cf24bba3 Mon Sep 17 00:00:00 2001 From: Peter Johnson Date: Wed, 21 Nov 2001 03:17:43 +0000 Subject: [PATCH] Polish up most directive support. This necessitated adding objfmt-specific data pointers to symrec for extern/common/etc. Also fixed parsing of direxpr; it didn't allow exprs with ID's before. svn path=/trunk/yasm/; revision=356 --- libyasm/coretype.h | 8 +++ libyasm/objfmt.h | 20 ++++++++ libyasm/symrec.c | 38 +++++++++++++- libyasm/symrec.h | 11 +--- modules/objfmts/dbg/dbg-objfmt.c | 76 ++++++++++++++++++++++++++- modules/objfmts/dbg/objfmt.c | 76 ++++++++++++++++++++++++++- modules/parsers/nasm/bison.y.in | 85 +++++++++++++++++++++---------- modules/parsers/nasm/nasm-bison.y | 85 +++++++++++++++++++++---------- src/coretype.h | 8 +++ src/objfmt.h | 20 ++++++++ src/objfmts/dbg/dbg-objfmt.c | 76 ++++++++++++++++++++++++++- src/objfmts/dbg/objfmt.c | 76 ++++++++++++++++++++++++++- src/parsers/nasm/bison.y.in | 85 +++++++++++++++++++++---------- src/parsers/nasm/nasm-bison.y | 85 +++++++++++++++++++++---------- src/symrec.c | 38 +++++++++++++- src/symrec.h | 11 +--- 16 files changed, 662 insertions(+), 136 deletions(-) diff --git a/libyasm/coretype.h b/libyasm/coretype.h index 3ce0bff3..0389d7ee 100644 --- a/libyasm/coretype.h +++ b/libyasm/coretype.h @@ -68,4 +68,12 @@ typedef enum { EXPR_IDENT /* no operation, just a value */ } ExprOp; +/* EXTERN and COMMON are mutually exclusive */ +typedef enum { + SYM_LOCAL = 0, /* default, local only */ + SYM_GLOBAL = 1 << 0, /* if it's declared GLOBAL */ + SYM_COMMON = 1 << 1, /* if it's declared COMMON */ + SYM_EXTERN = 1 << 2 /* if it's declared EXTERN */ +} SymVisibility; + #endif diff --git a/libyasm/objfmt.h b/libyasm/objfmt.h index e484dbd8..7b36c157 100644 --- a/libyasm/objfmt.h +++ b/libyasm/objfmt.h @@ -55,6 +55,26 @@ struct objfmt { void (*section_data_delete)(/*@only@*/ void *data); void (*section_data_print)(void *data); + + /*@null@*/ void *(*extern_data_new)(const char *name, /*@null@*/ + valparamhead *objext_valparams); + /*@null@*/ void *(*global_data_new)(const char *name, /*@null@*/ + valparamhead *objext_valparams); + /*@null@*/ void *(*common_data_new)(const char *name, + /*@only@*/ expr *size, /*@null@*/ + valparamhead *objext_valparams); + + /* It's only valid to pass this *one* SymVisibility (eg, vis is an enum not + * a bitmask). + */ + void (*declare_data_delete)(SymVisibility vis, /*@only@*/ void *data); + + /* Object format-specific directive support. Returns 1 if directive was + * not recognized. Returns 0 if directive was recognized, even if it + * wasn't valid. + */ + int (*directive)(const char *name, valparamhead *valparams, + /*@null@*/ valparamhead *objext_valparams); }; /* Generic functions for all object formats - implemented in src/objfmt.c */ diff --git a/libyasm/symrec.c b/libyasm/symrec.c index c426f5f4..70a611d5 100644 --- a/libyasm/symrec.c +++ b/libyasm/symrec.c @@ -37,6 +37,7 @@ #include "bytecode.h" #include "section.h" +#include "objfmt.h" /* DEFINED is set with EXTERN and COMMON below */ @@ -68,6 +69,12 @@ struct symrec { /*@dependent@*/ /*@null@*/ bytecode *bc; } label; } value; + + /* objfmt-specific data (related to visibility, so common/extern share + * a pointer, and global has its own pointer). + */ + /*@null@*/ /*@owned@*/ void *of_data_vis_ce; + /*@null@*/ /*@owned@*/ void *of_data_vis_g; }; /* The symbol table: a ternary tree. */ @@ -96,6 +103,8 @@ symrec_get_or_new(const char *name, int in_table) rec->filename = in_filename; rec->line = line_number; rec->visibility = SYM_LOCAL; + rec->of_data_vis_ce = NULL; + rec->of_data_vis_g = NULL; /*@-freshtrans -mustfree@*/ return rec; @@ -156,10 +165,12 @@ symrec_define_label(const char *name, section *sect, bytecode *precbc, } symrec * -symrec_declare(const char *name, SymVisibility vis) +symrec_declare(const char *name, SymVisibility vis, void *of_data) { symrec *rec = symrec_get_or_new(name, 1); + assert(cur_objfmt != NULL); + /* Don't allow EXTERN and COMMON if symbol has already been DEFINED. */ /* Also, EXTERN and COMMON are mutually exclusive. */ if (((rec->status & SYM_DEFINED) && !(rec->visibility & SYM_EXTERN)) || @@ -167,6 +178,8 @@ symrec_declare(const char *name, SymVisibility vis) ((rec->visibility & SYM_EXTERN) && (vis == SYM_COMMON))) { Error(_("duplicate definition of `%s'; first defined on line %d"), name, rec->line); + if (of_data) + cur_objfmt->declare_data_delete(vis, of_data); } else { rec->line = line_number; /* set line number of declaration */ rec->visibility |= vis; @@ -174,6 +187,20 @@ symrec_declare(const char *name, SymVisibility vis) /* If declared as COMMON or EXTERN, set as DEFINED. */ if ((vis == SYM_COMMON) || (vis == SYM_EXTERN)) rec->status |= SYM_DEFINED; + + if (of_data) { + switch (vis) { + case SYM_GLOBAL: + rec->of_data_vis_g = of_data; + break; + case SYM_COMMON: + case SYM_EXTERN: + rec->of_data_vis_ce = of_data; + break; + default: + InternalError(_("Unexpected vis value")); + } + } } return rec; } @@ -269,6 +296,15 @@ symrec_delete_one(/*@only@*/ void *d) xfree(sym->name); if (sym->type == SYM_EQU) expr_delete(sym->value.expn); + assert(cur_objfmt != NULL); + if (sym->of_data_vis_g && (sym->visibility & SYM_GLOBAL)) + cur_objfmt->declare_data_delete(SYM_GLOBAL, sym->of_data_vis_g); + if (sym->of_data_vis_ce && (sym->visibility & SYM_COMMON)) { + cur_objfmt->declare_data_delete(SYM_COMMON, sym->of_data_vis_ce); + sym->of_data_vis_ce = NULL; + } + if (sym->of_data_vis_ce && (sym->visibility & SYM_EXTERN)) + cur_objfmt->declare_data_delete(SYM_EXTERN, sym->of_data_vis_ce); xfree(sym); } diff --git a/libyasm/symrec.h b/libyasm/symrec.h index 8946275b..2d2c1497 100644 --- a/libyasm/symrec.h +++ b/libyasm/symrec.h @@ -22,14 +22,6 @@ #ifndef YASM_SYMREC_H #define YASM_SYMREC_H -/* EXTERN and COMMON are mutually exclusive */ -typedef enum { - SYM_LOCAL = 0, /* default, local only */ - SYM_GLOBAL = 1 << 0, /* if it's declared GLOBAL */ - SYM_COMMON = 1 << 1, /* if it's declared COMMON */ - SYM_EXTERN = 1 << 2 /* if it's declared EXTERN */ -} SymVisibility; - /*@dependent@*/ symrec *symrec_use(const char *name); /*@dependent@*/ symrec *symrec_define_equ(const char *name, /*@keep@*/ expr *e); @@ -39,7 +31,8 @@ typedef enum { section *sect, /*@dependent@*/ /*@null@*/ bytecode *precbc, int in_table); -/*@dependent@*/ symrec *symrec_declare(const char *name, SymVisibility vis); +/*@dependent@*/ symrec *symrec_declare(const char *name, SymVisibility vis, + /*@only@*/ /*@null@*/ void *of_data); /* Get the numeric 32-bit value of a symbol if possible. * Return value is IF POSSIBLE, not the value. diff --git a/modules/objfmts/dbg/dbg-objfmt.c b/modules/objfmts/dbg/dbg-objfmt.c index 825204ec..ab6a3349 100644 --- a/modules/objfmts/dbg/dbg-objfmt.c +++ b/modules/objfmts/dbg/dbg-objfmt.c @@ -82,6 +82,75 @@ dbg_objfmt_section_data_print(/*@unused@*/ void *data) { } +static /*@null@*/ void * +dbg_objfmt_extern_data_new(const char *name, /*@unused@*/ /*@null@*/ + valparamhead *objext_valparams) +{ + printf("extern_data_new(\"%s\")\n", name); + return NULL; +} + +static /*@null@*/ void * +dbg_objfmt_global_data_new(const char *name, /*@unused@*/ /*@null@*/ + valparamhead *objext_valparams) +{ + printf("global_data_new(\"%s\")\n", name); + return NULL; +} + +static /*@null@*/ void * +dbg_objfmt_common_data_new(const char *name, /*@only@*/ expr *size, + /*@unused@*/ /*@null@*/ + valparamhead *objext_valparams) +{ + printf("common_data_new(\"%s\",", name); + expr_print(size); + printf(")\n"); + return size; +} + +static void +dbg_objfmt_declare_data_delete(/*@unused@*/ SymVisibility vis, + /*@unused@*/ /*@only@*/ void *data) +{ + printf("declare_data_delete()\n"); + if (vis == SYM_COMMON) + expr_delete(data); + else + xfree(data); +} + +static int +dbg_objfmt_directive(const char *name, valparamhead *valparams, + /*@null@*/ valparamhead *objext_valparams) +{ + valparam *vp; + + printf("directive(\"%s\", valparams:\n", name); + vps_foreach(vp, valparams) { + printf(" (%s,", vp->val?vp->val:"(nil)"); + if (vp->param) + expr_print(vp->param); + else + printf("(nil)"); + printf(")\n"); + } + printf(" objext_valparams:\n"); + if (!objext_valparams) + printf(" (none)\n"); + else + vps_foreach(vp, objext_valparams) { + printf(" (%s,", vp->val?vp->val:"(nil)"); + if (vp->param) + expr_print(vp->param); + else + printf("(nil)"); + printf(")\n"); + } + + return 0; /* dbg format "recognizes" all directives */ +} + /* Define objfmt structure -- see objfmt.h for details */ objfmt dbg_objfmt = { "Trace of all info passed to object format module", @@ -90,5 +159,10 @@ objfmt dbg_objfmt = { 32, dbg_objfmt_sections_switch, dbg_objfmt_section_data_delete, - dbg_objfmt_section_data_print + dbg_objfmt_section_data_print, + dbg_objfmt_extern_data_new, + dbg_objfmt_global_data_new, + dbg_objfmt_common_data_new, + dbg_objfmt_declare_data_delete, + dbg_objfmt_directive }; diff --git a/modules/objfmts/dbg/objfmt.c b/modules/objfmts/dbg/objfmt.c index 825204ec..ab6a3349 100644 --- a/modules/objfmts/dbg/objfmt.c +++ b/modules/objfmts/dbg/objfmt.c @@ -82,6 +82,75 @@ dbg_objfmt_section_data_print(/*@unused@*/ void *data) { } +static /*@null@*/ void * +dbg_objfmt_extern_data_new(const char *name, /*@unused@*/ /*@null@*/ + valparamhead *objext_valparams) +{ + printf("extern_data_new(\"%s\")\n", name); + return NULL; +} + +static /*@null@*/ void * +dbg_objfmt_global_data_new(const char *name, /*@unused@*/ /*@null@*/ + valparamhead *objext_valparams) +{ + printf("global_data_new(\"%s\")\n", name); + return NULL; +} + +static /*@null@*/ void * +dbg_objfmt_common_data_new(const char *name, /*@only@*/ expr *size, + /*@unused@*/ /*@null@*/ + valparamhead *objext_valparams) +{ + printf("common_data_new(\"%s\",", name); + expr_print(size); + printf(")\n"); + return size; +} + +static void +dbg_objfmt_declare_data_delete(/*@unused@*/ SymVisibility vis, + /*@unused@*/ /*@only@*/ void *data) +{ + printf("declare_data_delete()\n"); + if (vis == SYM_COMMON) + expr_delete(data); + else + xfree(data); +} + +static int +dbg_objfmt_directive(const char *name, valparamhead *valparams, + /*@null@*/ valparamhead *objext_valparams) +{ + valparam *vp; + + printf("directive(\"%s\", valparams:\n", name); + vps_foreach(vp, valparams) { + printf(" (%s,", vp->val?vp->val:"(nil)"); + if (vp->param) + expr_print(vp->param); + else + printf("(nil)"); + printf(")\n"); + } + printf(" objext_valparams:\n"); + if (!objext_valparams) + printf(" (none)\n"); + else + vps_foreach(vp, objext_valparams) { + printf(" (%s,", vp->val?vp->val:"(nil)"); + if (vp->param) + expr_print(vp->param); + else + printf("(nil)"); + printf(")\n"); + } + + return 0; /* dbg format "recognizes" all directives */ +} + /* Define objfmt structure -- see objfmt.h for details */ objfmt dbg_objfmt = { "Trace of all info passed to object format module", @@ -90,5 +159,10 @@ objfmt dbg_objfmt = { 32, dbg_objfmt_sections_switch, dbg_objfmt_section_data_delete, - dbg_objfmt_section_data_print + dbg_objfmt_section_data_print, + dbg_objfmt_extern_data_new, + dbg_objfmt_global_data_new, + dbg_objfmt_common_data_new, + dbg_objfmt_declare_data_delete, + dbg_objfmt_directive }; diff --git a/modules/parsers/nasm/bison.y.in b/modules/parsers/nasm/bison.y.in index a4aa433e..7ea84816 100644 --- a/modules/parsers/nasm/bison.y.in +++ b/modules/parsers/nasm/bison.y.in @@ -235,8 +235,15 @@ directive_valparams: directive_valparam { } ; -directive_valparam: ID { vp_new($$, $1, NULL); } - | direxpr { vp_new($$, NULL, $1); } +directive_valparam: direxpr { + /* If direxpr is just an ID, put it in val and delete the expr */ + const /*@null@*/ symrec *vp_symrec; + if ((vp_symrec = expr_get_symrec(&$1, 0))) { + vp_new($$, xstrdup(symrec_get_name(vp_symrec)), NULL); + expr_delete($1); + } else + vp_new($$, NULL, $1); + } | ID '=' direxpr { vp_new($$, $1, $3); } ; @@ -480,6 +487,10 @@ target: expr { /* expr w/o FLTNUM and unary + and -, for use in directives */ direxpr: INTNUM { $$ = expr_new_ident(ExprInt($1)); } + | ID { + $$ = expr_new_ident(ExprSym(symrec_define_label($1, NULL, NULL, 0))); + xfree($1); + } | direxpr '|' direxpr { $$ = expr_new_tree($1, EXPR_OR, $3); } | direxpr '^' direxpr { $$ = expr_new_tree($1, EXPR_XOR, $3); } | direxpr '&' direxpr { $$ = expr_new_tree($1, EXPR_AND, $3); } @@ -605,12 +616,52 @@ static void nasm_parser_directive(const char *name, valparamhead *valparams, valparamhead *objext_valparams) { - valparam *vp; + valparam *vp, *vp2; const intnum *intn; long lval; assert(cur_objfmt != NULL); - if (strcasecmp(name, "section") == 0) { + + /* Handle (mostly) output-format independent directives here */ + if (strcasecmp(name, "extern") == 0) { + vp = vps_first(valparams); + if (vp->val) + symrec_declare(vp->val, SYM_EXTERN, + cur_objfmt->extern_data_new(vp->val, + objext_valparams)); + else + Error(_("invalid argument to [%s]"), "EXTERN"); + } else if (strcasecmp(name, "global") == 0) { + vp = vps_first(valparams); + if (vp->val) + symrec_declare(vp->val, SYM_GLOBAL, + cur_objfmt->global_data_new(vp->val, + objext_valparams)); + else + Error(_("invalid argument to [%s]"), "GLOBAL"); + } else if (strcasecmp(name, "common") == 0) { + vp = vps_first(valparams); + if (vp->val) { + vp2 = vps_next(vp); + if (!vp2 || (!vp2->val && !vp2->param)) + Error(_("no size specified in %s declaration"), "COMMON"); + else { + if (vp2->val) + symrec_declare(vp->val, SYM_COMMON, + cur_objfmt->common_data_new(vp->val, + expr_new_ident(ExprSym(symrec_use(vp2->val))), + objext_valparams)); + else if (vp2->param) { + symrec_declare(vp->val, SYM_COMMON, + cur_objfmt->common_data_new(vp->val, vp2->param, + objext_valparams)); + vp2->param = NULL; + } + } + } else + Error(_("invalid argument to [%s]"), "COMMON"); + } else if (strcasecmp(name, "section") == 0 || + strcasecmp(name, "segment") == 0) { section *new_section = cur_objfmt->sections_switch(&nasm_parser_sections, valparams, objext_valparams); @@ -620,6 +671,7 @@ nasm_parser_directive(const char *name, valparamhead *valparams, } else Error(_("invalid argument to [%s]"), "SECTION"); } else if (strcasecmp(name, "absolute") == 0) { + /* it can be just an ID or a complete expression, so handle both. */ vp = vps_first(valparams); if (vp->val) nasm_parser_cur_section = @@ -638,31 +690,8 @@ nasm_parser_directive(const char *name, valparamhead *valparams, x86_mode_bits = (unsigned char)lval; else Error(_("invalid argument to [%s]"), "BITS"); - } else { + } else if (cur_objfmt->directive(name, valparams, objext_valparams)) { Error(_("unrecognized directive [%s]"), name); -#if 0 - printf("Directive: Name=`%s'\n Val/Params:\n", name); - vps_foreach(vp, valparams) { - printf(" (%s,", vp->val?vp->val:"(nil)"); - if (vp->param) - expr_print(vp->param); - else - printf("(nil)"); - printf(")\n"); - } - printf(" Obj Ext Val/Params:\n"); - if (!objext_valparams) - printf(" (none)\n"); - else - vps_foreach(vp, objext_valparams) { - printf(" (%s,", vp->val?vp->val:"(nil)"); - if (vp->param) - expr_print(vp->param); - else - printf("(nil)"); - printf(")\n"); - } -#endif } vps_delete(valparams); diff --git a/modules/parsers/nasm/nasm-bison.y b/modules/parsers/nasm/nasm-bison.y index a4aa433e..7ea84816 100644 --- a/modules/parsers/nasm/nasm-bison.y +++ b/modules/parsers/nasm/nasm-bison.y @@ -235,8 +235,15 @@ directive_valparams: directive_valparam { } ; -directive_valparam: ID { vp_new($$, $1, NULL); } - | direxpr { vp_new($$, NULL, $1); } +directive_valparam: direxpr { + /* If direxpr is just an ID, put it in val and delete the expr */ + const /*@null@*/ symrec *vp_symrec; + if ((vp_symrec = expr_get_symrec(&$1, 0))) { + vp_new($$, xstrdup(symrec_get_name(vp_symrec)), NULL); + expr_delete($1); + } else + vp_new($$, NULL, $1); + } | ID '=' direxpr { vp_new($$, $1, $3); } ; @@ -480,6 +487,10 @@ target: expr { /* expr w/o FLTNUM and unary + and -, for use in directives */ direxpr: INTNUM { $$ = expr_new_ident(ExprInt($1)); } + | ID { + $$ = expr_new_ident(ExprSym(symrec_define_label($1, NULL, NULL, 0))); + xfree($1); + } | direxpr '|' direxpr { $$ = expr_new_tree($1, EXPR_OR, $3); } | direxpr '^' direxpr { $$ = expr_new_tree($1, EXPR_XOR, $3); } | direxpr '&' direxpr { $$ = expr_new_tree($1, EXPR_AND, $3); } @@ -605,12 +616,52 @@ static void nasm_parser_directive(const char *name, valparamhead *valparams, valparamhead *objext_valparams) { - valparam *vp; + valparam *vp, *vp2; const intnum *intn; long lval; assert(cur_objfmt != NULL); - if (strcasecmp(name, "section") == 0) { + + /* Handle (mostly) output-format independent directives here */ + if (strcasecmp(name, "extern") == 0) { + vp = vps_first(valparams); + if (vp->val) + symrec_declare(vp->val, SYM_EXTERN, + cur_objfmt->extern_data_new(vp->val, + objext_valparams)); + else + Error(_("invalid argument to [%s]"), "EXTERN"); + } else if (strcasecmp(name, "global") == 0) { + vp = vps_first(valparams); + if (vp->val) + symrec_declare(vp->val, SYM_GLOBAL, + cur_objfmt->global_data_new(vp->val, + objext_valparams)); + else + Error(_("invalid argument to [%s]"), "GLOBAL"); + } else if (strcasecmp(name, "common") == 0) { + vp = vps_first(valparams); + if (vp->val) { + vp2 = vps_next(vp); + if (!vp2 || (!vp2->val && !vp2->param)) + Error(_("no size specified in %s declaration"), "COMMON"); + else { + if (vp2->val) + symrec_declare(vp->val, SYM_COMMON, + cur_objfmt->common_data_new(vp->val, + expr_new_ident(ExprSym(symrec_use(vp2->val))), + objext_valparams)); + else if (vp2->param) { + symrec_declare(vp->val, SYM_COMMON, + cur_objfmt->common_data_new(vp->val, vp2->param, + objext_valparams)); + vp2->param = NULL; + } + } + } else + Error(_("invalid argument to [%s]"), "COMMON"); + } else if (strcasecmp(name, "section") == 0 || + strcasecmp(name, "segment") == 0) { section *new_section = cur_objfmt->sections_switch(&nasm_parser_sections, valparams, objext_valparams); @@ -620,6 +671,7 @@ nasm_parser_directive(const char *name, valparamhead *valparams, } else Error(_("invalid argument to [%s]"), "SECTION"); } else if (strcasecmp(name, "absolute") == 0) { + /* it can be just an ID or a complete expression, so handle both. */ vp = vps_first(valparams); if (vp->val) nasm_parser_cur_section = @@ -638,31 +690,8 @@ nasm_parser_directive(const char *name, valparamhead *valparams, x86_mode_bits = (unsigned char)lval; else Error(_("invalid argument to [%s]"), "BITS"); - } else { + } else if (cur_objfmt->directive(name, valparams, objext_valparams)) { Error(_("unrecognized directive [%s]"), name); -#if 0 - printf("Directive: Name=`%s'\n Val/Params:\n", name); - vps_foreach(vp, valparams) { - printf(" (%s,", vp->val?vp->val:"(nil)"); - if (vp->param) - expr_print(vp->param); - else - printf("(nil)"); - printf(")\n"); - } - printf(" Obj Ext Val/Params:\n"); - if (!objext_valparams) - printf(" (none)\n"); - else - vps_foreach(vp, objext_valparams) { - printf(" (%s,", vp->val?vp->val:"(nil)"); - if (vp->param) - expr_print(vp->param); - else - printf("(nil)"); - printf(")\n"); - } -#endif } vps_delete(valparams); diff --git a/src/coretype.h b/src/coretype.h index 3ce0bff3..0389d7ee 100644 --- a/src/coretype.h +++ b/src/coretype.h @@ -68,4 +68,12 @@ typedef enum { EXPR_IDENT /* no operation, just a value */ } ExprOp; +/* EXTERN and COMMON are mutually exclusive */ +typedef enum { + SYM_LOCAL = 0, /* default, local only */ + SYM_GLOBAL = 1 << 0, /* if it's declared GLOBAL */ + SYM_COMMON = 1 << 1, /* if it's declared COMMON */ + SYM_EXTERN = 1 << 2 /* if it's declared EXTERN */ +} SymVisibility; + #endif diff --git a/src/objfmt.h b/src/objfmt.h index e484dbd8..7b36c157 100644 --- a/src/objfmt.h +++ b/src/objfmt.h @@ -55,6 +55,26 @@ struct objfmt { void (*section_data_delete)(/*@only@*/ void *data); void (*section_data_print)(void *data); + + /*@null@*/ void *(*extern_data_new)(const char *name, /*@null@*/ + valparamhead *objext_valparams); + /*@null@*/ void *(*global_data_new)(const char *name, /*@null@*/ + valparamhead *objext_valparams); + /*@null@*/ void *(*common_data_new)(const char *name, + /*@only@*/ expr *size, /*@null@*/ + valparamhead *objext_valparams); + + /* It's only valid to pass this *one* SymVisibility (eg, vis is an enum not + * a bitmask). + */ + void (*declare_data_delete)(SymVisibility vis, /*@only@*/ void *data); + + /* Object format-specific directive support. Returns 1 if directive was + * not recognized. Returns 0 if directive was recognized, even if it + * wasn't valid. + */ + int (*directive)(const char *name, valparamhead *valparams, + /*@null@*/ valparamhead *objext_valparams); }; /* Generic functions for all object formats - implemented in src/objfmt.c */ diff --git a/src/objfmts/dbg/dbg-objfmt.c b/src/objfmts/dbg/dbg-objfmt.c index 825204ec..ab6a3349 100644 --- a/src/objfmts/dbg/dbg-objfmt.c +++ b/src/objfmts/dbg/dbg-objfmt.c @@ -82,6 +82,75 @@ dbg_objfmt_section_data_print(/*@unused@*/ void *data) { } +static /*@null@*/ void * +dbg_objfmt_extern_data_new(const char *name, /*@unused@*/ /*@null@*/ + valparamhead *objext_valparams) +{ + printf("extern_data_new(\"%s\")\n", name); + return NULL; +} + +static /*@null@*/ void * +dbg_objfmt_global_data_new(const char *name, /*@unused@*/ /*@null@*/ + valparamhead *objext_valparams) +{ + printf("global_data_new(\"%s\")\n", name); + return NULL; +} + +static /*@null@*/ void * +dbg_objfmt_common_data_new(const char *name, /*@only@*/ expr *size, + /*@unused@*/ /*@null@*/ + valparamhead *objext_valparams) +{ + printf("common_data_new(\"%s\",", name); + expr_print(size); + printf(")\n"); + return size; +} + +static void +dbg_objfmt_declare_data_delete(/*@unused@*/ SymVisibility vis, + /*@unused@*/ /*@only@*/ void *data) +{ + printf("declare_data_delete()\n"); + if (vis == SYM_COMMON) + expr_delete(data); + else + xfree(data); +} + +static int +dbg_objfmt_directive(const char *name, valparamhead *valparams, + /*@null@*/ valparamhead *objext_valparams) +{ + valparam *vp; + + printf("directive(\"%s\", valparams:\n", name); + vps_foreach(vp, valparams) { + printf(" (%s,", vp->val?vp->val:"(nil)"); + if (vp->param) + expr_print(vp->param); + else + printf("(nil)"); + printf(")\n"); + } + printf(" objext_valparams:\n"); + if (!objext_valparams) + printf(" (none)\n"); + else + vps_foreach(vp, objext_valparams) { + printf(" (%s,", vp->val?vp->val:"(nil)"); + if (vp->param) + expr_print(vp->param); + else + printf("(nil)"); + printf(")\n"); + } + + return 0; /* dbg format "recognizes" all directives */ +} + /* Define objfmt structure -- see objfmt.h for details */ objfmt dbg_objfmt = { "Trace of all info passed to object format module", @@ -90,5 +159,10 @@ objfmt dbg_objfmt = { 32, dbg_objfmt_sections_switch, dbg_objfmt_section_data_delete, - dbg_objfmt_section_data_print + dbg_objfmt_section_data_print, + dbg_objfmt_extern_data_new, + dbg_objfmt_global_data_new, + dbg_objfmt_common_data_new, + dbg_objfmt_declare_data_delete, + dbg_objfmt_directive }; diff --git a/src/objfmts/dbg/objfmt.c b/src/objfmts/dbg/objfmt.c index 825204ec..ab6a3349 100644 --- a/src/objfmts/dbg/objfmt.c +++ b/src/objfmts/dbg/objfmt.c @@ -82,6 +82,75 @@ dbg_objfmt_section_data_print(/*@unused@*/ void *data) { } +static /*@null@*/ void * +dbg_objfmt_extern_data_new(const char *name, /*@unused@*/ /*@null@*/ + valparamhead *objext_valparams) +{ + printf("extern_data_new(\"%s\")\n", name); + return NULL; +} + +static /*@null@*/ void * +dbg_objfmt_global_data_new(const char *name, /*@unused@*/ /*@null@*/ + valparamhead *objext_valparams) +{ + printf("global_data_new(\"%s\")\n", name); + return NULL; +} + +static /*@null@*/ void * +dbg_objfmt_common_data_new(const char *name, /*@only@*/ expr *size, + /*@unused@*/ /*@null@*/ + valparamhead *objext_valparams) +{ + printf("common_data_new(\"%s\",", name); + expr_print(size); + printf(")\n"); + return size; +} + +static void +dbg_objfmt_declare_data_delete(/*@unused@*/ SymVisibility vis, + /*@unused@*/ /*@only@*/ void *data) +{ + printf("declare_data_delete()\n"); + if (vis == SYM_COMMON) + expr_delete(data); + else + xfree(data); +} + +static int +dbg_objfmt_directive(const char *name, valparamhead *valparams, + /*@null@*/ valparamhead *objext_valparams) +{ + valparam *vp; + + printf("directive(\"%s\", valparams:\n", name); + vps_foreach(vp, valparams) { + printf(" (%s,", vp->val?vp->val:"(nil)"); + if (vp->param) + expr_print(vp->param); + else + printf("(nil)"); + printf(")\n"); + } + printf(" objext_valparams:\n"); + if (!objext_valparams) + printf(" (none)\n"); + else + vps_foreach(vp, objext_valparams) { + printf(" (%s,", vp->val?vp->val:"(nil)"); + if (vp->param) + expr_print(vp->param); + else + printf("(nil)"); + printf(")\n"); + } + + return 0; /* dbg format "recognizes" all directives */ +} + /* Define objfmt structure -- see objfmt.h for details */ objfmt dbg_objfmt = { "Trace of all info passed to object format module", @@ -90,5 +159,10 @@ objfmt dbg_objfmt = { 32, dbg_objfmt_sections_switch, dbg_objfmt_section_data_delete, - dbg_objfmt_section_data_print + dbg_objfmt_section_data_print, + dbg_objfmt_extern_data_new, + dbg_objfmt_global_data_new, + dbg_objfmt_common_data_new, + dbg_objfmt_declare_data_delete, + dbg_objfmt_directive }; diff --git a/src/parsers/nasm/bison.y.in b/src/parsers/nasm/bison.y.in index a4aa433e..7ea84816 100644 --- a/src/parsers/nasm/bison.y.in +++ b/src/parsers/nasm/bison.y.in @@ -235,8 +235,15 @@ directive_valparams: directive_valparam { } ; -directive_valparam: ID { vp_new($$, $1, NULL); } - | direxpr { vp_new($$, NULL, $1); } +directive_valparam: direxpr { + /* If direxpr is just an ID, put it in val and delete the expr */ + const /*@null@*/ symrec *vp_symrec; + if ((vp_symrec = expr_get_symrec(&$1, 0))) { + vp_new($$, xstrdup(symrec_get_name(vp_symrec)), NULL); + expr_delete($1); + } else + vp_new($$, NULL, $1); + } | ID '=' direxpr { vp_new($$, $1, $3); } ; @@ -480,6 +487,10 @@ target: expr { /* expr w/o FLTNUM and unary + and -, for use in directives */ direxpr: INTNUM { $$ = expr_new_ident(ExprInt($1)); } + | ID { + $$ = expr_new_ident(ExprSym(symrec_define_label($1, NULL, NULL, 0))); + xfree($1); + } | direxpr '|' direxpr { $$ = expr_new_tree($1, EXPR_OR, $3); } | direxpr '^' direxpr { $$ = expr_new_tree($1, EXPR_XOR, $3); } | direxpr '&' direxpr { $$ = expr_new_tree($1, EXPR_AND, $3); } @@ -605,12 +616,52 @@ static void nasm_parser_directive(const char *name, valparamhead *valparams, valparamhead *objext_valparams) { - valparam *vp; + valparam *vp, *vp2; const intnum *intn; long lval; assert(cur_objfmt != NULL); - if (strcasecmp(name, "section") == 0) { + + /* Handle (mostly) output-format independent directives here */ + if (strcasecmp(name, "extern") == 0) { + vp = vps_first(valparams); + if (vp->val) + symrec_declare(vp->val, SYM_EXTERN, + cur_objfmt->extern_data_new(vp->val, + objext_valparams)); + else + Error(_("invalid argument to [%s]"), "EXTERN"); + } else if (strcasecmp(name, "global") == 0) { + vp = vps_first(valparams); + if (vp->val) + symrec_declare(vp->val, SYM_GLOBAL, + cur_objfmt->global_data_new(vp->val, + objext_valparams)); + else + Error(_("invalid argument to [%s]"), "GLOBAL"); + } else if (strcasecmp(name, "common") == 0) { + vp = vps_first(valparams); + if (vp->val) { + vp2 = vps_next(vp); + if (!vp2 || (!vp2->val && !vp2->param)) + Error(_("no size specified in %s declaration"), "COMMON"); + else { + if (vp2->val) + symrec_declare(vp->val, SYM_COMMON, + cur_objfmt->common_data_new(vp->val, + expr_new_ident(ExprSym(symrec_use(vp2->val))), + objext_valparams)); + else if (vp2->param) { + symrec_declare(vp->val, SYM_COMMON, + cur_objfmt->common_data_new(vp->val, vp2->param, + objext_valparams)); + vp2->param = NULL; + } + } + } else + Error(_("invalid argument to [%s]"), "COMMON"); + } else if (strcasecmp(name, "section") == 0 || + strcasecmp(name, "segment") == 0) { section *new_section = cur_objfmt->sections_switch(&nasm_parser_sections, valparams, objext_valparams); @@ -620,6 +671,7 @@ nasm_parser_directive(const char *name, valparamhead *valparams, } else Error(_("invalid argument to [%s]"), "SECTION"); } else if (strcasecmp(name, "absolute") == 0) { + /* it can be just an ID or a complete expression, so handle both. */ vp = vps_first(valparams); if (vp->val) nasm_parser_cur_section = @@ -638,31 +690,8 @@ nasm_parser_directive(const char *name, valparamhead *valparams, x86_mode_bits = (unsigned char)lval; else Error(_("invalid argument to [%s]"), "BITS"); - } else { + } else if (cur_objfmt->directive(name, valparams, objext_valparams)) { Error(_("unrecognized directive [%s]"), name); -#if 0 - printf("Directive: Name=`%s'\n Val/Params:\n", name); - vps_foreach(vp, valparams) { - printf(" (%s,", vp->val?vp->val:"(nil)"); - if (vp->param) - expr_print(vp->param); - else - printf("(nil)"); - printf(")\n"); - } - printf(" Obj Ext Val/Params:\n"); - if (!objext_valparams) - printf(" (none)\n"); - else - vps_foreach(vp, objext_valparams) { - printf(" (%s,", vp->val?vp->val:"(nil)"); - if (vp->param) - expr_print(vp->param); - else - printf("(nil)"); - printf(")\n"); - } -#endif } vps_delete(valparams); diff --git a/src/parsers/nasm/nasm-bison.y b/src/parsers/nasm/nasm-bison.y index a4aa433e..7ea84816 100644 --- a/src/parsers/nasm/nasm-bison.y +++ b/src/parsers/nasm/nasm-bison.y @@ -235,8 +235,15 @@ directive_valparams: directive_valparam { } ; -directive_valparam: ID { vp_new($$, $1, NULL); } - | direxpr { vp_new($$, NULL, $1); } +directive_valparam: direxpr { + /* If direxpr is just an ID, put it in val and delete the expr */ + const /*@null@*/ symrec *vp_symrec; + if ((vp_symrec = expr_get_symrec(&$1, 0))) { + vp_new($$, xstrdup(symrec_get_name(vp_symrec)), NULL); + expr_delete($1); + } else + vp_new($$, NULL, $1); + } | ID '=' direxpr { vp_new($$, $1, $3); } ; @@ -480,6 +487,10 @@ target: expr { /* expr w/o FLTNUM and unary + and -, for use in directives */ direxpr: INTNUM { $$ = expr_new_ident(ExprInt($1)); } + | ID { + $$ = expr_new_ident(ExprSym(symrec_define_label($1, NULL, NULL, 0))); + xfree($1); + } | direxpr '|' direxpr { $$ = expr_new_tree($1, EXPR_OR, $3); } | direxpr '^' direxpr { $$ = expr_new_tree($1, EXPR_XOR, $3); } | direxpr '&' direxpr { $$ = expr_new_tree($1, EXPR_AND, $3); } @@ -605,12 +616,52 @@ static void nasm_parser_directive(const char *name, valparamhead *valparams, valparamhead *objext_valparams) { - valparam *vp; + valparam *vp, *vp2; const intnum *intn; long lval; assert(cur_objfmt != NULL); - if (strcasecmp(name, "section") == 0) { + + /* Handle (mostly) output-format independent directives here */ + if (strcasecmp(name, "extern") == 0) { + vp = vps_first(valparams); + if (vp->val) + symrec_declare(vp->val, SYM_EXTERN, + cur_objfmt->extern_data_new(vp->val, + objext_valparams)); + else + Error(_("invalid argument to [%s]"), "EXTERN"); + } else if (strcasecmp(name, "global") == 0) { + vp = vps_first(valparams); + if (vp->val) + symrec_declare(vp->val, SYM_GLOBAL, + cur_objfmt->global_data_new(vp->val, + objext_valparams)); + else + Error(_("invalid argument to [%s]"), "GLOBAL"); + } else if (strcasecmp(name, "common") == 0) { + vp = vps_first(valparams); + if (vp->val) { + vp2 = vps_next(vp); + if (!vp2 || (!vp2->val && !vp2->param)) + Error(_("no size specified in %s declaration"), "COMMON"); + else { + if (vp2->val) + symrec_declare(vp->val, SYM_COMMON, + cur_objfmt->common_data_new(vp->val, + expr_new_ident(ExprSym(symrec_use(vp2->val))), + objext_valparams)); + else if (vp2->param) { + symrec_declare(vp->val, SYM_COMMON, + cur_objfmt->common_data_new(vp->val, vp2->param, + objext_valparams)); + vp2->param = NULL; + } + } + } else + Error(_("invalid argument to [%s]"), "COMMON"); + } else if (strcasecmp(name, "section") == 0 || + strcasecmp(name, "segment") == 0) { section *new_section = cur_objfmt->sections_switch(&nasm_parser_sections, valparams, objext_valparams); @@ -620,6 +671,7 @@ nasm_parser_directive(const char *name, valparamhead *valparams, } else Error(_("invalid argument to [%s]"), "SECTION"); } else if (strcasecmp(name, "absolute") == 0) { + /* it can be just an ID or a complete expression, so handle both. */ vp = vps_first(valparams); if (vp->val) nasm_parser_cur_section = @@ -638,31 +690,8 @@ nasm_parser_directive(const char *name, valparamhead *valparams, x86_mode_bits = (unsigned char)lval; else Error(_("invalid argument to [%s]"), "BITS"); - } else { + } else if (cur_objfmt->directive(name, valparams, objext_valparams)) { Error(_("unrecognized directive [%s]"), name); -#if 0 - printf("Directive: Name=`%s'\n Val/Params:\n", name); - vps_foreach(vp, valparams) { - printf(" (%s,", vp->val?vp->val:"(nil)"); - if (vp->param) - expr_print(vp->param); - else - printf("(nil)"); - printf(")\n"); - } - printf(" Obj Ext Val/Params:\n"); - if (!objext_valparams) - printf(" (none)\n"); - else - vps_foreach(vp, objext_valparams) { - printf(" (%s,", vp->val?vp->val:"(nil)"); - if (vp->param) - expr_print(vp->param); - else - printf("(nil)"); - printf(")\n"); - } -#endif } vps_delete(valparams); diff --git a/src/symrec.c b/src/symrec.c index c426f5f4..70a611d5 100644 --- a/src/symrec.c +++ b/src/symrec.c @@ -37,6 +37,7 @@ #include "bytecode.h" #include "section.h" +#include "objfmt.h" /* DEFINED is set with EXTERN and COMMON below */ @@ -68,6 +69,12 @@ struct symrec { /*@dependent@*/ /*@null@*/ bytecode *bc; } label; } value; + + /* objfmt-specific data (related to visibility, so common/extern share + * a pointer, and global has its own pointer). + */ + /*@null@*/ /*@owned@*/ void *of_data_vis_ce; + /*@null@*/ /*@owned@*/ void *of_data_vis_g; }; /* The symbol table: a ternary tree. */ @@ -96,6 +103,8 @@ symrec_get_or_new(const char *name, int in_table) rec->filename = in_filename; rec->line = line_number; rec->visibility = SYM_LOCAL; + rec->of_data_vis_ce = NULL; + rec->of_data_vis_g = NULL; /*@-freshtrans -mustfree@*/ return rec; @@ -156,10 +165,12 @@ symrec_define_label(const char *name, section *sect, bytecode *precbc, } symrec * -symrec_declare(const char *name, SymVisibility vis) +symrec_declare(const char *name, SymVisibility vis, void *of_data) { symrec *rec = symrec_get_or_new(name, 1); + assert(cur_objfmt != NULL); + /* Don't allow EXTERN and COMMON if symbol has already been DEFINED. */ /* Also, EXTERN and COMMON are mutually exclusive. */ if (((rec->status & SYM_DEFINED) && !(rec->visibility & SYM_EXTERN)) || @@ -167,6 +178,8 @@ symrec_declare(const char *name, SymVisibility vis) ((rec->visibility & SYM_EXTERN) && (vis == SYM_COMMON))) { Error(_("duplicate definition of `%s'; first defined on line %d"), name, rec->line); + if (of_data) + cur_objfmt->declare_data_delete(vis, of_data); } else { rec->line = line_number; /* set line number of declaration */ rec->visibility |= vis; @@ -174,6 +187,20 @@ symrec_declare(const char *name, SymVisibility vis) /* If declared as COMMON or EXTERN, set as DEFINED. */ if ((vis == SYM_COMMON) || (vis == SYM_EXTERN)) rec->status |= SYM_DEFINED; + + if (of_data) { + switch (vis) { + case SYM_GLOBAL: + rec->of_data_vis_g = of_data; + break; + case SYM_COMMON: + case SYM_EXTERN: + rec->of_data_vis_ce = of_data; + break; + default: + InternalError(_("Unexpected vis value")); + } + } } return rec; } @@ -269,6 +296,15 @@ symrec_delete_one(/*@only@*/ void *d) xfree(sym->name); if (sym->type == SYM_EQU) expr_delete(sym->value.expn); + assert(cur_objfmt != NULL); + if (sym->of_data_vis_g && (sym->visibility & SYM_GLOBAL)) + cur_objfmt->declare_data_delete(SYM_GLOBAL, sym->of_data_vis_g); + if (sym->of_data_vis_ce && (sym->visibility & SYM_COMMON)) { + cur_objfmt->declare_data_delete(SYM_COMMON, sym->of_data_vis_ce); + sym->of_data_vis_ce = NULL; + } + if (sym->of_data_vis_ce && (sym->visibility & SYM_EXTERN)) + cur_objfmt->declare_data_delete(SYM_EXTERN, sym->of_data_vis_ce); xfree(sym); } diff --git a/src/symrec.h b/src/symrec.h index 8946275b..2d2c1497 100644 --- a/src/symrec.h +++ b/src/symrec.h @@ -22,14 +22,6 @@ #ifndef YASM_SYMREC_H #define YASM_SYMREC_H -/* EXTERN and COMMON are mutually exclusive */ -typedef enum { - SYM_LOCAL = 0, /* default, local only */ - SYM_GLOBAL = 1 << 0, /* if it's declared GLOBAL */ - SYM_COMMON = 1 << 1, /* if it's declared COMMON */ - SYM_EXTERN = 1 << 2 /* if it's declared EXTERN */ -} SymVisibility; - /*@dependent@*/ symrec *symrec_use(const char *name); /*@dependent@*/ symrec *symrec_define_equ(const char *name, /*@keep@*/ expr *e); @@ -39,7 +31,8 @@ typedef enum { section *sect, /*@dependent@*/ /*@null@*/ bytecode *precbc, int in_table); -/*@dependent@*/ symrec *symrec_declare(const char *name, SymVisibility vis); +/*@dependent@*/ symrec *symrec_declare(const char *name, SymVisibility vis, + /*@only@*/ /*@null@*/ void *of_data); /* Get the numeric 32-bit value of a symbol if possible. * Return value is IF POSSIBLE, not the value.