From: Jeff Law Date: Mon, 22 Nov 1993 10:37:02 +0000 (+0000) Subject: * Minimal support for reading SOM fixup streams. Allows X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=36456a67f8717421db8bbb2ef4b242ed7c423fa3;p=binutils-gdb.git * Minimal support for reading SOM fixup streams. Allows objdump -r to do something reasonable. * som.c (som_get_reloc_upper_bound): Implement. (som_canonicalize_reloc): Implement. (som_set_reloc_info, som_slurp_reloc_table): New functions. --- diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 3f73fc044a7..cec678e0968 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,11 @@ +Mon Nov 22 02:33:12 1993 Jeffrey A. Law (law@snake.cs.utah.edu) + + * Minimal support for reading SOM fixup streams. Allows + objdump -r to do something reasonable. + * som.c (som_get_reloc_upper_bound): Implement. + (som_canonicalize_reloc): Implement. + (som_set_reloc_info, som_slurp_reloc_table): New functions. + Fri Nov 19 14:34:04 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) * coff-a29k.c (a29k_reloc): For R_IREL, don't left shift diff --git a/bfd/som.c b/bfd/som.c index 05d74e97e5f..4c36fe720d9 100644 --- a/bfd/som.c +++ b/bfd/som.c @@ -118,6 +118,11 @@ static unsigned int som_get_symtab_upper_bound PARAMS ((bfd *)); static unsigned int som_canonicalize_reloc PARAMS ((bfd *, sec_ptr, arelent **, asymbol **)); static unsigned int som_get_reloc_upper_bound PARAMS ((bfd *, sec_ptr)); +static unsigned int som_set_reloc_info PARAMS ((unsigned char *, unsigned int, + arelent *, asection *, + asymbol **, boolean)); +static boolean som_slurp_reloc_table PARAMS ((bfd *, asection *, + asymbol **, boolean)); static unsigned int som_get_symtab PARAMS ((bfd *, asymbol **)); static asymbol * som_make_empty_symbol PARAMS ((bfd *)); static void som_print_symbol PARAMS ((bfd *, PTR, @@ -178,6 +183,438 @@ static boolean som_begin_writing PARAMS ((bfd *)); static const reloc_howto_type * som_bfd_reloc_type_lookup PARAMS ((bfd_arch_info_type *, bfd_reloc_code_real_type)); +/* About the relocation formatting table... + + There are 256 entries in the table, one for each possible + relocation opcode available in SOM. We index the table by + the relocation opcode. The names and operations are those + defined by a.out_800 (4). + + Right now this table is only used to count and perform minimal + processing on relocation streams so that they can be internalized + into BFD and symbolically printed by utilities. To make actual use + of them would be much more difficult, BFD's concept of relocations + is far too simple to handle SOM relocations. The basic assumption + that a relocation can be completely processed independent of other + relocations before an object file is written is invalid for SOM. + + The SOM relocations are meant to be processed as a stream, they + specify copying of data from the input section to the output section + while possibly modifying the data in some manner. They also can + specify that a variable number of zeros or uninitialized data be + inserted on in the output segment at the current offset. Some + relocations specify that some previous relocation be re-applied at + the current location in the input/output sections. And finally a number + of relocations have effects on other sections (R_ENTRY, R_EXIT, + R_UNWIND_AUX and a variety of others). There isn't even enough room + in the BFD relocation data structure to store enough information to + perform all the relocations. + + Each entry in the table has three fields. + + The first entry is an index into this "class" of relocations. This + index can then be used as a variable within the relocation itself. + + The second field is a format string which actually controls processing + of the relocation. It uses a simple postfix machine to do calculations + based on variables/constants found in the string and the relocation + stream. + + The third field specifys whether or not this relocation may use + a constant (V) from the previous R_DATA_OVERRIDE rather than a constant + stored in the instruction. + + Variables: + + L = input space byte count + D = index into class of relocations + M = output space byte count + N = statement number (unused?) + O = stack operation + R = parameter relocation bits + S = symbol index + U = 64 bits of stack unwind and frame size info (we only keep 32 bits) + V = a literal constant (usually used in the next relocation) + P = a previous relocation + + Lower case letters (starting with 'b') refer to following + bytes in the relocation stream. 'b' is the next 1 byte, + c is the next 2 bytes, d is the next 3 bytes, etc... + This is the variable part of the relocation entries that + makes our life a living hell. + + numerical constants are also used in the format string. Note + the constants are represented in decimal. + + '+', "*" and "=" represents the obvious postfix operators. + '<' represents a left shift. + + Stack Operations: + + Parameter Relocation Bits: + + Unwind Entries: + + Previous Relocations: The index field represents which in the queue + of 4 previous fixups should be re-applied. + + Literal Constants: These are generally used to represent addend + parts of relocations when these constants are not stored in the + fields of the instructions themselves. For example the instruction + addil foo-$global$-0x1234 would use an override for "0x1234" rather + than storing it into the addil itself. */ + +struct fixup_format +{ + int D; + char *format; +}; + +static const struct fixup_format som_fixup_formats[256] = +{ + /* R_NO_RELOCATION */ + 0, "LD1+4*=", /* 0x00 */ + 1, "LD1+4*=", /* 0x01 */ + 2, "LD1+4*=", /* 0x02 */ + 3, "LD1+4*=", /* 0x03 */ + 4, "LD1+4*=", /* 0x04 */ + 5, "LD1+4*=", /* 0x05 */ + 6, "LD1+4*=", /* 0x06 */ + 7, "LD1+4*=", /* 0x07 */ + 8, "LD1+4*=", /* 0x08 */ + 9, "LD1+4*=", /* 0x09 */ + 10, "LD1+4*=", /* 0x0a */ + 11, "LD1+4*=", /* 0x0b */ + 12, "LD1+4*=", /* 0x0c */ + 13, "LD1+4*=", /* 0x0d */ + 14, "LD1+4*=", /* 0x0e */ + 15, "LD1+4*=", /* 0x0f */ + 16, "LD1+4*=", /* 0x10 */ + 17, "LD1+4*=", /* 0x11 */ + 18, "LD1+4*=", /* 0x12 */ + 19, "LD1+4*=", /* 0x13 */ + 20, "LD1+4*=", /* 0x14 */ + 21, "LD1+4*=", /* 0x15 */ + 22, "LD1+4*=", /* 0x16 */ + 23, "LD1+4*=", /* 0x17 */ + 0, "LD8_raw_size = aux_hdrp->exec_tsize; - data->_raw_size = aux_hdrp->exec_dsize; - bss->_raw_size = aux_hdrp->exec_bsize; - - text->flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_CODE); - data->flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS); - bss->flags = (SEC_ALLOC | SEC_IS_COMMON); - - /* The virtual memory addresses of the sections */ - text->vma = aux_hdrp->exec_tmem; - data->vma = aux_hdrp->exec_dmem; - bss->vma = aux_hdrp->exec_bfill; - - /* The file offsets of the sections */ - text->filepos = aux_hdrp->exec_tfile; - data->filepos = aux_hdrp->exec_dfile; - - /* The file offsets of the relocation info */ - text->rel_filepos = 0; - data->rel_filepos = 0; - /* Set BFD flags based on what information is available in the SOM. */ abfd->flags = NO_FLAGS; if (! file_hdrp->entry_offset) @@ -1156,13 +1559,19 @@ setup_sections (abfd, file_hdr) if (subspace.dup_common || subspace.is_common) subspace_asect->flags |= SEC_IS_COMMON; - else + else if (subspace.subspace_length > 0) subspace_asect->flags |= SEC_HAS_CONTENTS; if (subspace.is_loadable) subspace_asect->flags |= SEC_ALLOC | SEC_LOAD; if (subspace.code_only) subspace_asect->flags |= SEC_CODE; + /* Both file_loc_init_value and initialization_length will + be zero for a BSS like subspace. */ + if (subspace.file_loc_init_value == 0 + && subspace.initialization_length == 0) + subspace_asect->flags &= ~(SEC_DATA | SEC_LOAD); + /* This subspace has relocations. The fixup_request_quantity is a byte count for the number of entries in the relocation stream; it is not the actual number @@ -1184,7 +1593,7 @@ setup_sections (abfd, file_hdr) subspace_asect->vma = subspace.subspace_start; subspace_asect->_cooked_size = subspace.subspace_length; - subspace_asect->_raw_size = subspace.initialization_length; + subspace_asect->_raw_size = subspace.subspace_length; subspace_asect->alignment_power = log2 (subspace.alignment); subspace_asect->filepos = subspace.file_loc_init_value; } @@ -2737,14 +3146,14 @@ som_slurp_symbol_table (abfd) switch (bufp->symbol_type) { case ST_ENTRY: + case ST_PRI_PROG: + case ST_SEC_PROG: + case ST_MILLICODE: sym->symbol.flags |= BSF_FUNCTION; sym->symbol.value &= ~0x3; break; - case ST_PRI_PROG: - case ST_SEC_PROG: case ST_STUB: - case ST_MILLICODE: case ST_CODE: sym->symbol.value &= ~0x3; @@ -2783,9 +3192,10 @@ som_slurp_symbol_table (abfd) } /* Mark symbols left around by the debugger. */ - if (strlen (sym->symbol.name) >= 3 + if (strlen (sym->symbol.name) >= 2 && sym->symbol.name[0] == 'L' - && (sym->symbol.name[2] == '$' || sym->symbol.name[3] == '$')) + && (sym->symbol.name[1] == '$' || sym->symbol.name[2] == '$' + || sym->symbol.name[3] == '$')) sym->symbol.flags |= BSF_DEBUGGING; /* Note increment at bottom of loop, since we skip some symbols @@ -2872,17 +3282,346 @@ som_print_symbol (ignore_abfd, afile, symbol, how) } } +/* Count or process variable-length SOM fixup records. + + To avoid code duplication we use this code both to compute the number + of relocations requested by a stream, and to internalize the stream. + + When computing the number of relocations requested by a stream the + variables rptr, section, and symbols have no meaning. + + Return the number of relocations requested by the fixup stream. When + not just counting + + This needs at least two or three more passes to get it cleaned up. */ + +static unsigned int +som_set_reloc_info (fixup, end, internal_relocs, section, symbols, just_count) + unsigned char *fixup; + unsigned int end; + arelent *internal_relocs; + asection *section; + asymbol **symbols; + boolean just_count; +{ + unsigned int op, varname; + unsigned char *end_fixups = &fixup[end]; + const struct fixup_format *fp; + char *cp; + unsigned char *save_fixup; + int variables[26], stack[20], c, v, count, prev_fixup, *sp; + const int *subop; + arelent *rptr= internal_relocs; + unsigned int offset = just_count ? 0 : section->vma; + +#define var(c) variables[(c) - 'A'] +#define push(v) (*sp++ = (v)) +#define pop() (*--sp) +#define emptystack() (sp == stack) + + som_initialize_reloc_queue (reloc_queue); + bzero (variables, sizeof (variables)); + bzero (stack, sizeof (stack)); + count = 0; + prev_fixup = 0; + sp = stack; + + while (fixup < end_fixups) + { + + /* Save pointer to the start of this fixup. We'll use + it later to determine if it is necessary to put this fixup + on the queue. */ + save_fixup = fixup; + + /* Get the fixup code and its associated format. */ + op = *fixup++; + fp = &som_fixup_formats[op]; + + /* Handle a request for a previous fixup. */ + if (*fp->format == 'P') + { + /* Get pointer to the beginning of the prev fixup, move + the repeated fixup to the head of the queue. */ + fixup = reloc_queue[fp->D].reloc; + som_reloc_queue_fix (reloc_queue, fp->D); + prev_fixup = 1; + + /* Get the fixup code and its associated format. */ + op = *fixup++; + fp = &som_fixup_formats[op]; + } + + /* If we are not just counting, set some reasonable defaults. */ + if (! just_count) + { + rptr->address = offset; + rptr->howto = &som_hppa_howto_table[op]; + rptr->addend = 0; + } + + /* Set default input length to 0. Get the opcode class index + into D. */ + var ('L') = 0; + var ('D') = fp->D; + + /* Get the opcode format. */ + cp = fp->format; + + /* Process the format string. Parsing happens in two phases, + parse RHS, then assign to LHS. Repeat until no more + characters in the format string. */ + while (*cp) + { + /* The variable this pass is going to compute a value for. */ + varname = *cp++; + + /* Start processing RHS. Continue until a NULL or '=' is found. */ + do + { + c = *cp++; + + /* If this is a variable, push it on the stack. */ + if (isupper (c)) + push (var (c)); + + /* If this is a lower case letter, then it represents + additional data from the fixup stream to be pushed onto + the stack. */ + else if (islower (c)) + { + for (v = 0; c > 'a'; --c) + v = (v << 8) | *fixup++; + push (v); + } + + /* A decimal constant. Push it on the stack. */ + else if (isdigit (c)) + { + v = c - '0'; + while (isdigit (*cp)) + v = (v * 10) + (*cp++ - '0'); + push (v); + } + else + + /* An operator. Pop two two values from the stack and + use them as operands to the given operation. Push + the result of the operation back on the stack. */ + switch (c) + { + case '+': + v = pop (); + v += pop (); + push (v); + break; + case '*': + v = pop (); + v *= pop (); + push (v); + break; + case '<': + v = pop (); + v = pop () << v; + push (v); + break; + default: + abort (); + } + } + while (*cp && *cp != '='); + + /* Move over the equal operator. */ + cp++; + + /* Pop the RHS off the stack. */ + c = pop (); + + /* Perform the assignment. */ + var (varname) = c; + + /* Handle side effects. and special 'O' stack cases. */ + switch (varname) + { + /* Consume some bytes from the input space. */ + case 'L': + offset += c; + break; + /* A symbol to use in the relocation. Make a note + of this if we are not just counting. */ + case 'S': + if (! just_count) + rptr->sym_ptr_ptr = &symbols[c]; + break; + /* Handle the linker expression stack. */ + case 'O': + switch (op) + { + case R_COMP1: + subop = comp1_opcodes; + break; + case R_COMP2: + subop = comp2_opcodes; + break; + case R_COMP3: + subop = comp3_opcodes; + break; + default: + abort (); + } + while (*subop <= (unsigned char) c) + ++subop; + --subop; + break; + default: + break; + } + } + + /* If we used a previous fixup, clean up after it. */ + if (prev_fixup) + { + fixup = save_fixup + 1; + prev_fixup = 0; + } + /* Queue it. */ + else if (fixup > save_fixup + 1) + som_reloc_queue_insert (save_fixup, fixup - save_fixup, reloc_queue); + + /* We do not pass R_DATA_OVERRIDE or R_NO_RELOCATION + fixups to BFD. */ + if (som_hppa_howto_table[op].type != R_DATA_OVERRIDE + && som_hppa_howto_table[op].type != R_NO_RELOCATION) + { + /* Done with a single reloction. Loop back to the top. */ + if (! just_count) + { + rptr->addend = var ('V'); + rptr++; + } + count++; + /* Now that we've handled a "full" relocation, reset + some state. */ + bzero (variables, sizeof (variables)); + bzero (stack, sizeof (stack)); + } + } + return count; + +#undef var +#undef push +#undef pop +#undef emptystack +} + +/* Read in the relocs (aka fixups in SOM terms) for a section. + + som_get_reloc_upper_bound calls this routine with JUST_COUNT + set to true to indicate it only needs a count of the number + of actual relocations. */ + +static boolean +som_slurp_reloc_table (abfd, section, symbols, just_count) + bfd *abfd; + asection *section; + asymbol **symbols; + boolean just_count; +{ + char *external_relocs; + unsigned int fixup_stream_size; + arelent *internal_relocs; + unsigned int num_relocs; + + fixup_stream_size = som_section_data (section)->reloc_size; + /* If there were no relocations, then there is nothing to do. */ + if (section->reloc_count == 0) + return true; + + /* If reloc_count is -1, then the relocation stream has not been + parsed. We must do so now to know how many relocations exist. */ + if (section->reloc_count == -1) + { + external_relocs = (char *) bfd_zalloc (abfd, fixup_stream_size); + if (external_relocs == (char *) NULL) + { + bfd_error = no_memory; + return false; + } + /* Read in the external forms. */ + if (bfd_seek (abfd, + obj_som_reloc_filepos (abfd) + section->rel_filepos, + SEEK_SET) + != 0) + { + bfd_error = system_call_error; + return false; + } + if (bfd_read (external_relocs, 1, fixup_stream_size, abfd) + != fixup_stream_size) + { + bfd_error = system_call_error; + return false; + } + /* Let callers know how many relocations found. + also save the relocation stream as we will + need it again. */ + section->reloc_count = som_set_reloc_info (external_relocs, + fixup_stream_size, + NULL, NULL, NULL, true); + + som_section_data (section)->reloc_stream = external_relocs; + } + + /* If the caller only wanted a count, then return now. */ + if (just_count) + return true; + + num_relocs = section->reloc_count; + external_relocs = som_section_data (section)->reloc_stream; + /* Return saved information about the relocations if it is available. */ + if (section->relocation != (arelent *) NULL) + return true; + + internal_relocs = (arelent *) bfd_zalloc (abfd, + num_relocs * sizeof (arelent)); + if (internal_relocs == (arelent *) NULL) + { + bfd_error = no_memory; + return false; + } + + /* Process and internalize the relocations. */ + som_set_reloc_info (external_relocs, fixup_stream_size, + internal_relocs, section, symbols, false); + + /* Save our results and return success. */ + section->relocation = internal_relocs; + return (true); +} + +/* Return the number of bytes required to store the relocation + information associated with the given section. */ + static unsigned int som_get_reloc_upper_bound (abfd, asect) bfd *abfd; sec_ptr asect; { - fprintf (stderr, "som_get_reloc_upper_bound unimplemented\n"); - fflush (stderr); - abort (); - return (0); + /* If section has relocations, then read in the relocation stream + and parse it to determine how many relocations exist. */ + if (asect->flags & SEC_RELOC) + { + if (som_slurp_reloc_table (abfd, asect, NULL, true)) + return (asect->reloc_count + 1) * sizeof (arelent); + } + /* Either there are no relocations or an error occurred while + reading and parsing the relocation stream. */ + return 0; } +/* Convert relocations from SOM (external) form into BFD internal + form. Return the number of relocations. */ + static unsigned int som_canonicalize_reloc (abfd, section, relptr, symbols) bfd *abfd; @@ -2890,9 +3629,22 @@ som_canonicalize_reloc (abfd, section, relptr, symbols) arelent **relptr; asymbol **symbols; { - fprintf (stderr, "som_canonicalize_reloc unimplemented\n"); - fflush (stderr); - abort (); + arelent *tblptr; + int count; + + if (som_slurp_reloc_table (abfd, section, symbols, false) == false) + return 0; + + count = section->reloc_count; + tblptr = section->relocation; + if (tblptr == (arelent *) NULL) + return 0; + + while (count--) + *relptr++ = tblptr++; + + *relptr = (arelent *) NULL; + return section->reloc_count; } extern bfd_target som_vec;