From 7895f447310b0128ec78d53dd9b38556233163b2 Mon Sep 17 00:00:00 2001 From: pk Date: Sat, 20 Nov 1993 22:15:54 +0000 Subject: [PATCH] Fixed bug in tc-i386.c which in rare but unpredictable circumstances would screw up PC relative offsets to _GLOBAL_SYMBOL_TABLE_ (caused by me not quite understanding the inner workings of this phenomenon called `obstack'). Thanks to Thomas Eberhardt for creating rare and unpredictable circumstances. Changes to obj-aout.c to handle non-absolute `.size' expressions and to set the `n_other' field of symbols to the symbols type, as given by `.type' directives. --- gnu/usr.bin/gas/config/aout.h | 6 +++ gnu/usr.bin/gas/config/obj-aout.c | 76 ++++++++++++++++++++++++------- gnu/usr.bin/gas/config/obj-aout.h | 5 +- gnu/usr.bin/gas/config/tc-i386.c | 48 +++++++++++-------- 4 files changed, 99 insertions(+), 36 deletions(-) diff --git a/gnu/usr.bin/gas/config/aout.h b/gnu/usr.bin/gas/config/aout.h index 4c9863b95afd..23b085adaaa1 100644 --- a/gnu/usr.bin/gas/config/aout.h +++ b/gnu/usr.bin/gas/config/aout.h @@ -64,6 +64,12 @@ enum reloc_type { #endif /* not TC_SPARC */ NO_RELOC, +#ifdef TC_I386 + /* Used internally by gas */ + RELOC_GOT, + RELOC_GOTOFF, +#endif + #endif /* not TC_I860 */ #endif /* not TC_M88K */ }; diff --git a/gnu/usr.bin/gas/config/obj-aout.c b/gnu/usr.bin/gas/config/obj-aout.c index c0a470e9d800..30eb2d150036 100644 --- a/gnu/usr.bin/gas/config/obj-aout.c +++ b/gnu/usr.bin/gas/config/obj-aout.c @@ -99,7 +99,7 @@ const pseudo_typeS obj_pseudo_table[] = { { "scl", s_ignore, 0 }, { "size", s_size, 0 }, { "tag", s_ignore, 0 }, - { "type", s_ignore, 0 }, + { "type", s_type, 0 }, { "val", s_ignore, 0 }, { "version", s_ignore, 0 }, @@ -228,9 +228,43 @@ symbolS *symbol_rootP; temp = S_GET_NAME(symbolP); S_SET_OFFSET(symbolP, symbolP->sy_name_offset); + /* + * Put aux info in lower four bits of `n_other' field + * Do this only now, because things like S_IS_DEFINED() + * depend on S_GET_OTHER() for some unspecified reason. + */ + if (symbolP->sy_aux) + S_SET_OTHER(symbolP, (symbolP->sy_aux & 0xf)); + /* Any symbol still undefined and is not a dbg symbol is made N_EXT. */ - if (!S_IS_DEBUG(symbolP) && !S_IS_DEFINED(symbolP)) S_SET_EXTERNAL(symbolP); + if (!S_IS_DEBUG(symbolP) && !S_IS_DEFINED(symbolP)) + S_SET_EXTERNAL(symbolP); + if (S_GET_TYPE(symbolP) == N_SIZE) { + expressionS *exp = (expressionS*)symbolP->sy_sizexp; + long size = 0; + + if (exp == NULL) { + as_bad("Internal error: no size expression"); + return; + } + + switch (exp->X_seg) { + case SEG_ABSOLUTE: + size = exp->X_add_number; + break; + case SEG_DIFFERENCE: + size = S_GET_VALUE(exp->X_add_symbol) - + S_GET_VALUE(exp->X_subtract_symbol) + + exp->X_add_number; + break; + default: + as_bad("Unsupported .size expression"); + break; + } + S_SET_VALUE(symbolP, size); + } + obj_symbol_to_chars(where, symbolP); S_SET_NAME(symbolP,temp); } @@ -458,6 +492,8 @@ object_headers *headers; * symbols with no name (stabd's?) * symbols with debug info in their N_TYPE + * symbols marked "forceout" (to force out local `L' + symbols in PIC code) Symbols that don't are: * symbols that are registers @@ -506,31 +542,39 @@ object_headers *headers; /* * If symbol has a known size, output an extra symbol * of type N_SIZE and with the same name. + * We cannot evaluate the size expression just yet, as + * some its terms may not have had their final values + * set. We defer this until `obj_emit_symbols()' */ - if (symbolP->sy_size && flagseen['k']) { - symbolS *addme; -#ifdef USE_NSIZE_PREFIX /*XXX*/ + if (flagseen['k'] && + S_GET_TYPE(symbolP) != N_SIZE && +#ifndef GRACE_PERIOD_EXPIRED + /*Can be enabled when no more old ld's around*/ + (symbolP->sy_aux == AUX_OBJECT) && +#endif + symbolP->sy_sizexp) { + + symbolS *addme; + + /* Put a new symbol on the chain */ +#ifdef NSIZE_PREFIX /*XXX*/ char buf[BUFSIZ]; - /* - * Changed my mind, make name: "=symbol" - */ - buf[0] = '='; + buf[0] = NSIZE_PREFIX; strncpy(buf+1, S_GET_NAME(symbolP), BUFSIZ-2); addme = symbol_make(buf); #else addme = symbol_make(S_GET_NAME(symbolP)); #endif -#if 0 - S_SET_SEGMENT(addme, SEG_SIZE); -#endif + /* Set type and transfer size expression */ addme->sy_symbol.n_type = N_SIZE; - S_SET_VALUE(addme, symbolP->sy_size); - /* Set external if symbolP is ? */ -#if 1 + addme->sy_sizexp = symbolP->sy_sizexp; + symbolP->sy_sizexp = NULL; + + /* Set external if symbolP is */ if (S_IS_EXTERN(symbolP)) S_SET_EXTERNAL(addme); -#endif + } symbolPP = &(symbol_next(symbolP)); } else { diff --git a/gnu/usr.bin/gas/config/obj-aout.h b/gnu/usr.bin/gas/config/obj-aout.h index 4c91f9da62b4..299dee2663d6 100644 --- a/gnu/usr.bin/gas/config/obj-aout.h +++ b/gnu/usr.bin/gas/config/obj-aout.h @@ -17,7 +17,7 @@ License along with GAS; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ /* - * $Id: obj-aout.h,v 1.1 1993/10/02 20:58:55 pk Exp $ + * $Id: obj-aout.h,v 1.2 1993/11/20 22:15:59 pk Exp $ */ @@ -39,6 +39,9 @@ extern const segT N_TYPE_seg[]; #define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE (OMAGIC) #endif /* DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE */ +/* First character of operand in `.type' directives */ +#define TYPE_OPERAND_FMT '@' + /* SYMBOL TABLE */ /* Symbol table entry data type */ diff --git a/gnu/usr.bin/gas/config/tc-i386.c b/gnu/usr.bin/gas/config/tc-i386.c index 9a6e1644eb7f..79a13a3fe231 100644 --- a/gnu/usr.bin/gas/config/tc-i386.c +++ b/gnu/usr.bin/gas/config/tc-i386.c @@ -25,7 +25,7 @@ */ #ifndef lint -static char rcsid[] = "$Id: tc-i386.c,v 1.3 1993/10/27 00:14:50 pk Exp $"; +static char rcsid[] = "$Id: tc-i386.c,v 1.4 1993/11/20 22:16:01 pk Exp $"; #endif #include "as.h" @@ -1191,30 +1191,35 @@ char *line; * Remember # of opcode bytes to put in pcrel_adjust * for use in _GLOBAL_OFFSET_TABLE_ expressions. */ - long opoffset = 0; - if (flagseen['k']) - opoffset = obstack_next_free(&frags) - frag_now->fr_literal; + int nopbytes = 0; #endif /* First the prefix bytes. */ for (q = i.prefix; q < i.prefix + i.prefixes; q++) { p = frag_more (1); + nopbytes += 1; md_number_to_chars (p, (unsigned int) *q, 1); } /* Now the opcode; be careful about word order here! */ if (fits_in_unsigned_byte(t->base_opcode)) { + nopbytes += 1; FRAG_APPEND_1_CHAR (t->base_opcode); } else if (fits_in_unsigned_word(t->base_opcode)) { p = frag_more (2); + nopbytes += 2; /* put out high byte first: can't use md_number_to_chars! */ *p++ = (t->base_opcode >> 8) & 0xff; *p = t->base_opcode & 0xff; } else { /* opcode is either 3 or 4 bytes */ if (t->base_opcode & 0xff000000) { p = frag_more (4); + nopbytes += 4; *p++ = (t->base_opcode >> 24) & 0xff; - } else p = frag_more (3); + } else { + p = frag_more (3); + nopbytes += 3; + } *p++ = (t->base_opcode >> 16) & 0xff; *p++ = (t->base_opcode >> 8) & 0xff; *p = (t->base_opcode ) & 0xff; @@ -1223,20 +1228,18 @@ char *line; /* Now the modrm byte and base index byte (if present). */ if (t->opcode_modifier & Modrm) { p = frag_more (1); + nopbytes += 1; /* md_number_to_chars (p, i.rm, 1); */ md_number_to_chars (p, (i.rm.regmem<<0 | i.rm.reg<<3 | i.rm.mode<<6), 1); /* If i.rm.regmem == ESP (4) && i.rm.mode != Mode 3 (Register mode) ==> need second modrm byte. */ if (i.rm.regmem == ESCAPE_TO_TWO_BYTE_ADDRESSING && i.rm.mode != 3) { p = frag_more (1); + nopbytes += 1; /* md_number_to_chars (p, i.bi, 1); */ md_number_to_chars (p,(i.bi.base<<0 | i.bi.index<<3 | i.bi.scale<<6), 1); } } -#ifdef PIC - if (flagseen['k']) - opoffset = obstack_next_free(&frags) - frag_now->fr_literal - opoffset; -#endif if (i.disp_operands) { register unsigned int n; @@ -1264,8 +1267,7 @@ char *line; i.disps[n]->X_add_number, 0, i.disp_reloc[n], i.disps[n]->X_got_symbol); #ifdef PIC if (i.disps[n]->X_got_symbol) { - fixP->fx_pcrel_adjust = opoffset; - opoffset = 0; + fixP->fx_pcrel_adjust = nopbytes; } #endif } @@ -1307,8 +1309,7 @@ char *line; i.imms[n]->X_add_number, 0, NO_RELOC, i.imms[n]->X_got_symbol); #ifdef PIC if (i.imms[n]->X_got_symbol) { - fixP->fx_pcrel_adjust = opoffset; - opoffset = 0; + fixP->fx_pcrel_adjust = nopbytes; } #endif } @@ -1615,13 +1616,13 @@ char *operand_string; strcat(tmpbuf, cp+1+3); *cp = '@'; } else if (strncmp(cp+1, "GOTOFF", 6) == 0) { - i.disp_reloc[this_operand] = RELOC_GLOB_DAT; + i.disp_reloc[this_operand] = RELOC_GOTOFF; *cp = '\0'; strcpy(tmpbuf, input_line_pointer); strcat(tmpbuf, cp+1+6); *cp = '@'; } else if (strncmp(cp+1, "GOT", 3) == 0) { - i.disp_reloc[this_operand] = RELOC_GLOB_DAT; + i.disp_reloc[this_operand] = RELOC_GOT; *cp = '\0'; strcpy(tmpbuf, input_line_pointer); strcat(tmpbuf, cp+1+3); @@ -1634,7 +1635,7 @@ char *operand_string; #endif exp_seg = expression(exp); #ifdef PIC - if (i.disp_reloc[this_operand] == RELOC_GLOB_DAT) + if (i.disp_reloc[this_operand] == RELOC_GOTOFF) exp->X_add_symbol->sy_forceout = 1; #endif if (*input_line_pointer) @@ -2044,11 +2045,20 @@ relax_addressT segment_address_in_file; r_symbolnum = fixP->fx_addsy->sy_number; extrn_bit = 1; break; - case RELOC_GLOB_DAT: + case RELOC_GOT: extra_bits = (1 << 4) & 0x10; /* r_baserel */ r_symbolnum = fixP->fx_addsy->sy_number; - if (S_IS_EXTERNAL(fixP->fx_addsy)) - extrn_bit = 1; + if (!extrn_bit && !S_IS_EXTERNAL(fixP->fx_addsy)) + as_warn("GOT relocation burb: `%s' should be global", + S_GET_NAME(fixP->fx_addsy)); + extrn_bit = 1; + break; + case RELOC_GOTOFF: + extra_bits = (1 << 4) & 0x10; /* r_baserel */ + r_symbolnum = fixP->fx_addsy->sy_number; + if (extrn_bit || S_IS_EXTERNAL(fixP->fx_addsy)) + as_warn("GOT relocation burb: `%s' should be static", + S_GET_NAME(fixP->fx_addsy)); break; case RELOC_JMP_TBL: extra_bits = (1 << 5) & 0x20; /* r_jmptable */