| /* BFD back-end for i386 a.out binaries under LynxOS. | 
 |    Copyright (C) 1990-2024 Free Software Foundation, Inc. | 
 |  | 
 |    This file is part of BFD, the Binary File Descriptor library. | 
 |  | 
 |    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 3 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., 51 Franklin Street - Fifth Floor, Boston, | 
 |    MA 02110-1301, USA.  */ | 
 |  | 
 | #define TEXT_START_ADDR 0 | 
 | #define TARGET_PAGE_SIZE 4096 | 
 | #define SEGMENT_SIZE TARGET_PAGE_SIZE | 
 | #define DEFAULT_ARCH bfd_arch_i386 | 
 |  | 
 | /* Do not "beautify" the CONCAT* macro args.  Traditional C will not | 
 |    remove whitespace added here, and thus will fail to concatenate | 
 |    the tokens.  */ | 
 | #define MY(OP) CONCAT2 (i386_aout_lynx_,OP) | 
 | #define TARGETNAME "a.out-i386-lynx" | 
 |  | 
 | #include "sysdep.h" | 
 | #include "bfd.h" | 
 | #include "libbfd.h" | 
 |  | 
 | #ifndef WRITE_HEADERS | 
 | #define WRITE_HEADERS(abfd, execp)					\ | 
 |   {									\ | 
 |     if (adata(abfd).magic == undecided_magic)				\ | 
 |       NAME (aout, adjust_sizes_and_vmas) (abfd);			\ | 
 | 									\ | 
 |     execp->a_syms = bfd_get_symcount (abfd) * EXTERNAL_NLIST_SIZE;	\ | 
 |     execp->a_entry = bfd_get_start_address (abfd);			\ | 
 | 									\ | 
 |     execp->a_trsize = ((obj_textsec (abfd)->reloc_count)		\ | 
 | 		       * obj_reloc_entry_size (abfd));			\ | 
 |     execp->a_drsize = ((obj_datasec (abfd)->reloc_count)		\ | 
 | 		       * obj_reloc_entry_size (abfd));			\ | 
 |     if (!NAME (aout, swap_exec_header_out) (abfd, execp, &exec_bytes))	\ | 
 |       return false;							\ | 
 | 									\ | 
 |     if (bfd_seek (abfd, 0, SEEK_SET) != 0				\ | 
 | 	|| bfd_write (&exec_bytes, EXEC_BYTES_SIZE,			\ | 
 | 		      abfd) != EXEC_BYTES_SIZE)				\ | 
 |       return false;							\ | 
 |     /* Now write out reloc info, followed by syms and strings.  */	\ | 
 | 									\ | 
 |     if (bfd_get_outsymbols (abfd) != NULL				\ | 
 | 	&& bfd_get_symcount (abfd) != 0)				\ | 
 |       {									\ | 
 | 	if (bfd_seek (abfd, N_SYMOFF (execp), SEEK_SET) != 0)		\ | 
 | 	  return false;							\ | 
 | 									\ | 
 | 	if (! NAME (aout, write_syms) (abfd))				\ | 
 | 	  return false;							\ | 
 |       }									\ | 
 | 									\ | 
 |     if (bfd_seek (abfd, N_TRELOFF (execp), SEEK_SET) != 0)		\ | 
 |       return false;							\ | 
 |     if (!NAME (lynx, squirt_out_relocs) (abfd, obj_textsec (abfd)))	\ | 
 |       return false;							\ | 
 | 									\ | 
 |     if (bfd_seek (abfd, N_DRELOFF (execp), SEEK_SET) != 0)		\ | 
 |       return false;							\ | 
 |     if (!NAME (lynx, squirt_out_relocs) (abfd, obj_datasec (abfd)))	\ | 
 |       return false;							\ | 
 |   } | 
 | #endif | 
 |  | 
 | #include "libaout.h" | 
 | #include "aout/aout64.h" | 
 |  | 
 |  | 
 | #ifdef LYNX_CORE | 
 |  | 
 | char *lynx_core_file_failing_command (); | 
 | int lynx_core_file_failing_signal (); | 
 | bool lynx_core_file_matches_executable_p (); | 
 | bfd_cleanup lynx_core_file_p (); | 
 |  | 
 | #define	MY_core_file_failing_command lynx_core_file_failing_command | 
 | #define	MY_core_file_failing_signal lynx_core_file_failing_signal | 
 | #define	MY_core_file_matches_executable_p lynx_core_file_matches_executable_p | 
 | #define	MY_core_file_p lynx_core_file_p | 
 |  | 
 | #endif /* LYNX_CORE */ | 
 |  | 
 |  | 
 | #define KEEPIT udata.i | 
 |  | 
 | extern reloc_howto_type aout_32_ext_howto_table[]; | 
 | extern reloc_howto_type aout_32_std_howto_table[]; | 
 |  | 
 | /* Standard reloc stuff */ | 
 | /* Output standard relocation information to a file in target byte order. */ | 
 |  | 
 | static void | 
 | NAME(lynx,swap_std_reloc_out) (bfd *abfd, | 
 | 			       arelent *g, | 
 | 			       struct reloc_std_external *natptr) | 
 | { | 
 |   int r_index; | 
 |   asymbol *sym = *(g->sym_ptr_ptr); | 
 |   int r_extern; | 
 |   unsigned int r_length; | 
 |   int r_pcrel; | 
 |   int r_baserel, r_jmptable, r_relative; | 
 |   asection *output_section = sym->section->output_section; | 
 |  | 
 |   PUT_WORD (abfd, g->address, natptr->r_address); | 
 |  | 
 |   r_length = bfd_log2 (bfd_get_reloc_size (g->howto)); | 
 |   r_pcrel = (int) g->howto->pc_relative;	/* Relative to PC? */ | 
 |   /* r_baserel, r_jmptable, r_relative???  FIXME-soon */ | 
 |   r_baserel = 0; | 
 |   r_jmptable = 0; | 
 |   r_relative = 0; | 
 |  | 
 |   /* name was clobbered by aout_write_syms to be symbol index */ | 
 |  | 
 |   /* If this relocation is relative to a symbol then set the | 
 |      r_index to the symbols index, and the r_extern bit. | 
 |  | 
 |      Absolute symbols can come in in two ways, either as an offset | 
 |      from the abs section, or as a symbol which has an abs value. | 
 |      check for that here | 
 |   */ | 
 |  | 
 |   if (bfd_is_com_section (output_section) | 
 |       || bfd_is_abs_section (output_section) | 
 |       || bfd_is_und_section (output_section)) | 
 |     { | 
 |       if (bfd_abs_section_ptr->symbol == sym) | 
 | 	{ | 
 | 	  /* Whoops, looked like an abs symbol, but is really an offset | 
 | 	     from the abs section */ | 
 | 	  r_index = 0; | 
 | 	  r_extern = 0; | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  /* Fill in symbol */ | 
 | 	  r_extern = 1; | 
 | 	  r_index = (*g->sym_ptr_ptr)->KEEPIT; | 
 | 	} | 
 |     } | 
 |   else | 
 |     { | 
 |       /* Just an ordinary section */ | 
 |       r_extern = 0; | 
 |       r_index = output_section->target_index; | 
 |     } | 
 |  | 
 |   /* now the fun stuff */ | 
 |   if (bfd_header_big_endian (abfd)) | 
 |     { | 
 |       natptr->r_index[0] = r_index >> 16; | 
 |       natptr->r_index[1] = r_index >> 8; | 
 |       natptr->r_index[2] = r_index; | 
 |       natptr->r_type[0] = | 
 | 	(r_extern ? RELOC_STD_BITS_EXTERN_BIG : 0) | 
 | 	| (r_pcrel ? RELOC_STD_BITS_PCREL_BIG : 0) | 
 | 	| (r_baserel ? RELOC_STD_BITS_BASEREL_BIG : 0) | 
 | 	| (r_jmptable ? RELOC_STD_BITS_JMPTABLE_BIG : 0) | 
 | 	| (r_relative ? RELOC_STD_BITS_RELATIVE_BIG : 0) | 
 | 	| (r_length << RELOC_STD_BITS_LENGTH_SH_BIG); | 
 |     } | 
 |   else | 
 |     { | 
 |       natptr->r_index[2] = r_index >> 16; | 
 |       natptr->r_index[1] = r_index >> 8; | 
 |       natptr->r_index[0] = r_index; | 
 |       natptr->r_type[0] = | 
 | 	(r_extern ? RELOC_STD_BITS_EXTERN_LITTLE : 0) | 
 | 	| (r_pcrel ? RELOC_STD_BITS_PCREL_LITTLE : 0) | 
 | 	| (r_baserel ? RELOC_STD_BITS_BASEREL_LITTLE : 0) | 
 | 	| (r_jmptable ? RELOC_STD_BITS_JMPTABLE_LITTLE : 0) | 
 | 	| (r_relative ? RELOC_STD_BITS_RELATIVE_LITTLE : 0) | 
 | 	| (r_length << RELOC_STD_BITS_LENGTH_SH_LITTLE); | 
 |     } | 
 | } | 
 |  | 
 |  | 
 | /* Extended stuff */ | 
 | /* Output extended relocation information to a file in target byte order. */ | 
 |  | 
 | static void | 
 | NAME(lynx,swap_ext_reloc_out) (bfd *abfd, | 
 | 			       arelent *g, | 
 | 			       struct reloc_ext_external *natptr) | 
 | { | 
 |   int r_index; | 
 |   int r_extern; | 
 |   unsigned int r_type; | 
 |   unsigned int r_addend; | 
 |   asymbol *sym = *(g->sym_ptr_ptr); | 
 |   asection *output_section = sym->section->output_section; | 
 |  | 
 |   PUT_WORD (abfd, g->address, natptr->r_address); | 
 |  | 
 |   r_type = (unsigned int) g->howto->type; | 
 |  | 
 |   r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma; | 
 |  | 
 |  | 
 |   /* If this relocation is relative to a symbol then set the | 
 |      r_index to the symbols index, and the r_extern bit. | 
 |  | 
 |      Absolute symbols can come in in two ways, either as an offset | 
 |      from the abs section, or as a symbol which has an abs value. | 
 |      check for that here | 
 |      */ | 
 |  | 
 |   if (bfd_is_com_section (output_section) | 
 |       || bfd_is_abs_section (output_section) | 
 |       || bfd_is_und_section (output_section)) | 
 |     { | 
 |       if (bfd_abs_section_ptr->symbol == sym) | 
 | 	{ | 
 | 	  /* Whoops, looked like an abs symbol, but is really an offset | 
 | 	 from the abs section */ | 
 | 	  r_index = 0; | 
 | 	  r_extern = 0; | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  r_extern = 1; | 
 | 	  r_index = (*g->sym_ptr_ptr)->KEEPIT; | 
 | 	} | 
 |     } | 
 |   else | 
 |     { | 
 |       /* Just an ordinary section */ | 
 |       r_extern = 0; | 
 |       r_index = output_section->target_index; | 
 |     } | 
 |  | 
 |  | 
 |   /* now the fun stuff */ | 
 |   if (bfd_header_big_endian (abfd)) | 
 |     { | 
 |       natptr->r_index[0] = r_index >> 16; | 
 |       natptr->r_index[1] = r_index >> 8; | 
 |       natptr->r_index[2] = r_index; | 
 |       natptr->r_type[0] = | 
 | 	(r_extern ? RELOC_EXT_BITS_EXTERN_BIG : 0) | 
 | 	| (r_type << RELOC_EXT_BITS_TYPE_SH_BIG); | 
 |     } | 
 |   else | 
 |     { | 
 |       natptr->r_index[2] = r_index >> 16; | 
 |       natptr->r_index[1] = r_index >> 8; | 
 |       natptr->r_index[0] = r_index; | 
 |       natptr->r_type[0] = | 
 | 	(r_extern ? RELOC_EXT_BITS_EXTERN_LITTLE : 0) | 
 | 	| (r_type << RELOC_EXT_BITS_TYPE_SH_LITTLE); | 
 |     } | 
 |  | 
 |   PUT_WORD (abfd, r_addend, natptr->r_addend); | 
 | } | 
 |  | 
 | /* BFD deals internally with all things based from the section they're | 
 |    in. so, something in 10 bytes into a text section  with a base of | 
 |    50 would have a symbol (.text+10) and know .text vma was 50. | 
 |  | 
 |    Aout keeps all it's symbols based from zero, so the symbol would | 
 |    contain 60. This macro subs the base of each section from the value | 
 |    to give the true offset from the section */ | 
 |  | 
 |  | 
 | #define MOVE_ADDRESS(ad)						\ | 
 |   if (r_extern)								\ | 
 |     {									\ | 
 |       /* undefined symbol */						\ | 
 |       if (symbols != NULL && r_index < bfd_get_symcount (abfd))		\ | 
 | 	cache_ptr->sym_ptr_ptr = symbols + r_index;			\ | 
 |       else								\ | 
 | 	cache_ptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;	\ | 
 |       cache_ptr->addend = ad;						\ | 
 |     }									\ | 
 |   else									\ | 
 |     {									\ | 
 |       /* defined, section relative. replace symbol with pointer to	\ | 
 | 	 symbol which points to section  */				\ | 
 |       switch (r_index)							\ | 
 | 	{								\ | 
 | 	case N_TEXT:							\ | 
 | 	case N_TEXT | N_EXT:						\ | 
 | 	  cache_ptr->sym_ptr_ptr  = obj_textsec(abfd)->symbol_ptr_ptr;	\ | 
 | 	  cache_ptr->addend = ad  - su->textsec->vma;			\ | 
 | 	  break;							\ | 
 | 	case N_DATA:							\ | 
 | 	case N_DATA | N_EXT:						\ | 
 | 	  cache_ptr->sym_ptr_ptr  = obj_datasec(abfd)->symbol_ptr_ptr;	\ | 
 | 	  cache_ptr->addend = ad - su->datasec->vma;			\ | 
 | 	  break;							\ | 
 | 	case N_BSS:							\ | 
 | 	case N_BSS | N_EXT:						\ | 
 | 	  cache_ptr->sym_ptr_ptr  = obj_bsssec(abfd)->symbol_ptr_ptr;	\ | 
 | 	  cache_ptr->addend = ad - su->bsssec->vma;			\ | 
 | 	  break;							\ | 
 | 	default:							\ | 
 | 	case N_ABS:							\ | 
 | 	case N_ABS | N_EXT:						\ | 
 | 	  cache_ptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;	\ | 
 | 	  cache_ptr->addend = ad;					\ | 
 | 	  break;							\ | 
 | 	}								\ | 
 |     }									\ | 
 |  | 
 | static void | 
 | NAME(lynx,swap_ext_reloc_in) (bfd *abfd, | 
 | 			      struct reloc_ext_external *bytes, | 
 | 			      arelent *cache_ptr, | 
 | 			      asymbol **symbols, | 
 | 			      bfd_size_type symcount ATTRIBUTE_UNUSED) | 
 | { | 
 |   unsigned int r_index; | 
 |   int r_extern; | 
 |   unsigned int r_type; | 
 |   struct aoutdata *su = &(abfd->tdata.aout_data->a); | 
 |  | 
 |   cache_ptr->address = (GET_SWORD (abfd, bytes->r_address)); | 
 |  | 
 |   r_index = bytes->r_index[1]; | 
 |   r_extern = (0 != (bytes->r_index[0] & RELOC_EXT_BITS_EXTERN_BIG)); | 
 |   r_type = (bytes->r_index[0] & RELOC_EXT_BITS_TYPE_BIG) | 
 |     >> RELOC_EXT_BITS_TYPE_SH_BIG; | 
 |  | 
 |   cache_ptr->howto = aout_32_ext_howto_table + r_type; | 
 |   MOVE_ADDRESS (GET_SWORD (abfd, bytes->r_addend)); | 
 | } | 
 |  | 
 | static void | 
 | NAME(lynx,swap_std_reloc_in) (bfd *abfd, | 
 | 			      struct reloc_std_external *bytes, | 
 | 			      arelent *cache_ptr, | 
 | 			      asymbol **symbols, | 
 | 			      bfd_size_type symcount ATTRIBUTE_UNUSED) | 
 | { | 
 |   unsigned int r_index; | 
 |   int r_extern; | 
 |   unsigned int r_length; | 
 |   int r_pcrel; | 
 |   struct aoutdata *su = &(abfd->tdata.aout_data->a); | 
 |  | 
 |   cache_ptr->address = H_GET_32 (abfd, bytes->r_address); | 
 |  | 
 |   r_index = bytes->r_index[1]; | 
 |   r_extern = (0 != (bytes->r_index[0] & RELOC_STD_BITS_EXTERN_BIG)); | 
 |   r_pcrel = (0 != (bytes->r_index[0] & RELOC_STD_BITS_PCREL_BIG)); | 
 |   r_length = (bytes->r_index[0] & RELOC_STD_BITS_LENGTH_BIG) | 
 |     >> RELOC_STD_BITS_LENGTH_SH_BIG; | 
 |  | 
 |   cache_ptr->howto = aout_32_std_howto_table + r_length + 4 * r_pcrel; | 
 |   /* FIXME-soon:  Roll baserel, jmptable, relative bits into howto setting */ | 
 |  | 
 |   MOVE_ADDRESS (0); | 
 | } | 
 |  | 
 | /* Reloc hackery */ | 
 |  | 
 | static bool | 
 | NAME(lynx,slurp_reloc_table) (bfd *abfd, | 
 | 			      sec_ptr asect, | 
 | 			      asymbol **symbols) | 
 | { | 
 |   bfd_size_type count; | 
 |   bfd_size_type reloc_size; | 
 |   void * relocs; | 
 |   arelent *reloc_cache; | 
 |   size_t each_size; | 
 |  | 
 |   if (asect->relocation) | 
 |     return true; | 
 |  | 
 |   if (asect->flags & SEC_CONSTRUCTOR) | 
 |     return true; | 
 |  | 
 |   if (asect == obj_datasec (abfd)) | 
 |     { | 
 |       reloc_size = exec_hdr (abfd)->a_drsize; | 
 |       goto doit; | 
 |     } | 
 |  | 
 |   if (asect == obj_textsec (abfd)) | 
 |     { | 
 |       reloc_size = exec_hdr (abfd)->a_trsize; | 
 |       goto doit; | 
 |     } | 
 |  | 
 |   bfd_set_error (bfd_error_invalid_operation); | 
 |   return false; | 
 |  | 
 |  doit: | 
 |   if (bfd_seek (abfd, asect->rel_filepos, SEEK_SET) != 0) | 
 |     return false; | 
 |   each_size = obj_reloc_entry_size (abfd); | 
 |  | 
 |   count = reloc_size / each_size; | 
 |  | 
 |  | 
 |   reloc_cache = (arelent *) bfd_zmalloc (count * sizeof (arelent)); | 
 |   if (!reloc_cache && count != 0) | 
 |     return false; | 
 |  | 
 |   relocs = _bfd_alloc_and_read (abfd, reloc_size, reloc_size); | 
 |   if (!relocs && reloc_size != 0) | 
 |     { | 
 |       free (reloc_cache); | 
 |       return false; | 
 |     } | 
 |  | 
 |   if (each_size == RELOC_EXT_SIZE) | 
 |     { | 
 |       struct reloc_ext_external *rptr = (struct reloc_ext_external *) relocs; | 
 |       unsigned int counter = 0; | 
 |       arelent *cache_ptr = reloc_cache; | 
 |  | 
 |       for (; counter < count; counter++, rptr++, cache_ptr++) | 
 | 	{ | 
 | 	  NAME(lynx,swap_ext_reloc_in) (abfd, rptr, cache_ptr, symbols, | 
 | 					(bfd_size_type) bfd_get_symcount (abfd)); | 
 | 	} | 
 |     } | 
 |   else | 
 |     { | 
 |       struct reloc_std_external *rptr = (struct reloc_std_external *) relocs; | 
 |       unsigned int counter = 0; | 
 |       arelent *cache_ptr = reloc_cache; | 
 |  | 
 |       for (; counter < count; counter++, rptr++, cache_ptr++) | 
 | 	{ | 
 | 	  NAME(lynx,swap_std_reloc_in) (abfd, rptr, cache_ptr, symbols, | 
 | 					(bfd_size_type) bfd_get_symcount (abfd)); | 
 | 	} | 
 |  | 
 |     } | 
 |  | 
 |   bfd_release (abfd, relocs); | 
 |   asect->relocation = reloc_cache; | 
 |   asect->reloc_count = count; | 
 |   return true; | 
 | } | 
 |  | 
 |  | 
 |  | 
 | /* Write out a relocation section into an object file.  */ | 
 |  | 
 | static bool | 
 | NAME(lynx,squirt_out_relocs) (bfd *abfd, asection *section) | 
 | { | 
 |   arelent **generic; | 
 |   unsigned char *native, *natptr; | 
 |   size_t each_size; | 
 |   unsigned int count = section->reloc_count; | 
 |   bfd_size_type natsize; | 
 |  | 
 |   if (count == 0) | 
 |     return true; | 
 |  | 
 |   each_size = obj_reloc_entry_size (abfd); | 
 |   natsize = count; | 
 |   natsize *= each_size; | 
 |   native = (unsigned char *) bfd_zalloc (abfd, natsize); | 
 |   if (!native) | 
 |     return false; | 
 |  | 
 |   generic = section->orelocation; | 
 |  | 
 |   if (each_size == RELOC_EXT_SIZE) | 
 |     { | 
 |       for (natptr = native; | 
 | 	   count != 0; | 
 | 	   --count, natptr += each_size, ++generic) | 
 | 	NAME(lynx,swap_ext_reloc_out) (abfd, *generic, (struct reloc_ext_external *) natptr); | 
 |     } | 
 |   else | 
 |     { | 
 |       for (natptr = native; | 
 | 	   count != 0; | 
 | 	   --count, natptr += each_size, ++generic) | 
 | 	NAME(lynx,swap_std_reloc_out) (abfd, *generic, (struct reloc_std_external *) natptr); | 
 |     } | 
 |  | 
 |   if (bfd_write (native, natsize, abfd) != natsize) | 
 |     { | 
 |       bfd_release (abfd, native); | 
 |       return false; | 
 |     } | 
 |   bfd_release (abfd, native); | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | /* This is stupid.  This function should be a boolean predicate */ | 
 | static long | 
 | NAME(lynx,canonicalize_reloc) (bfd *abfd, | 
 | 			       sec_ptr section, | 
 | 			       arelent **relptr, | 
 | 			       asymbol **symbols) | 
 | { | 
 |   arelent *tblptr = section->relocation; | 
 |   unsigned int count; | 
 |  | 
 |   if (!(tblptr || NAME(lynx,slurp_reloc_table) (abfd, section, symbols))) | 
 |     return -1; | 
 |  | 
 |   if (section->flags & SEC_CONSTRUCTOR) | 
 |     { | 
 |       arelent_chain *chain = section->constructor_chain; | 
 |       for (count = 0; count < section->reloc_count; count++) | 
 | 	{ | 
 | 	  *relptr++ = &chain->relent; | 
 | 	  chain = chain->next; | 
 | 	} | 
 |     } | 
 |   else | 
 |     { | 
 |       tblptr = section->relocation; | 
 |  | 
 |       for (count = 0; count++ < section->reloc_count;) | 
 | 	{ | 
 | 	  *relptr++ = tblptr++; | 
 | 	} | 
 |     } | 
 |   *relptr = 0; | 
 |  | 
 |   return section->reloc_count; | 
 | } | 
 |  | 
 | #define MY_canonicalize_reloc NAME(lynx,canonicalize_reloc) | 
 |  | 
 | #include "aout-target.h" |