From 4a81b56152631cda9dc351cb4d2f61f395ee4414 Mon Sep 17 00:00:00 2001 From: David Henkel-Wallace Date: Thu, 21 Mar 1991 21:11:25 +0000 Subject: [PATCH] Initial revision --- bfd/COPYING | 249 +++++ bfd/ChangeLog | 314 ++++++ bfd/Makefile | 158 +++ bfd/TODO | 49 + bfd/aout.c | 1904 +++++++++++++++++++++++++++++++++++ bfd/archive.c | 1223 ++++++++++++++++++++++ bfd/archures.c | 368 +++++++ bfd/archures.h | 41 + bfd/bfd.c | 882 ++++++++++++++++ bfd/cache.c | 200 ++++ bfd/coff-code.h | 2561 +++++++++++++++++++++++++++++++++++++++++++++++ bfd/coff-i960.c | 270 +++++ bfd/libaout.h | 80 ++ bfd/libbfd.c | 332 ++++++ bfd/libbfd.h | 160 +++ bfd/libcoff.h | 62 ++ bfd/misc.c | 98 ++ bfd/misc.h | 93 ++ bfd/opncls.c | 281 ++++++ bfd/srec.c | 464 +++++++++ bfd/sunos.c | 1904 +++++++++++++++++++++++++++++++++++ bfd/targets.c | 50 + 22 files changed, 11743 insertions(+) create mode 100644 bfd/COPYING create mode 100644 bfd/ChangeLog create mode 100755 bfd/Makefile create mode 100644 bfd/TODO create mode 100755 bfd/aout.c create mode 100644 bfd/archive.c create mode 100644 bfd/archures.c create mode 100755 bfd/archures.h create mode 100644 bfd/bfd.c create mode 100644 bfd/cache.c create mode 100755 bfd/coff-code.h create mode 100644 bfd/coff-i960.c create mode 100644 bfd/libaout.h create mode 100644 bfd/libbfd.c create mode 100644 bfd/libbfd.h create mode 100644 bfd/libcoff.h create mode 100755 bfd/misc.c create mode 100755 bfd/misc.h create mode 100644 bfd/opncls.c create mode 100644 bfd/srec.c create mode 100644 bfd/sunos.c create mode 100644 bfd/targets.c diff --git a/bfd/COPYING b/bfd/COPYING new file mode 100644 index 00000000000..9a170375811 --- /dev/null +++ b/bfd/COPYING @@ -0,0 +1,249 @@ + + GNU GENERAL PUBLIC LICENSE + Version 1, February 1989 + + Copyright (C) 1989 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The license agreements of most software companies try to keep users +at the mercy of those companies. By contrast, our General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. The +General Public License applies to the Free Software Foundation's +software and to any other program whose authors commit to using it. +You can use it for your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Specifically, the General Public License is designed to make +sure that you have the freedom to give away or sell copies of free +software, that you receive source code or can get it if you want it, +that you can change the software or use pieces of it in new free +programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of a such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must tell them their rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any program or other work which +contains a notice placed by the copyright holder saying it may be +distributed under the terms of this General Public License. The +"Program", below, refers to any such program or work, and a "work based +on the Program" means either the Program or any work containing the +Program or a portion of it, either verbatim or with modifications. Each +licensee is addressed as "you". + + 1. You may copy and distribute verbatim copies of the Program's source +code as you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice and +disclaimer of warranty; keep intact all the notices that refer to this +General Public License and to the absence of any warranty; and give any +other recipients of the Program a copy of this General Public License +along with the Program. You may charge a fee for the physical act of +transferring a copy. + + 2. You may modify your copy or copies of the Program or any portion of +it, and copy and distribute such modifications under the terms of Paragraph +1 above, provided that you also do the following: + + a) cause the modified files to carry prominent notices stating that + you changed the files and the date of any change; and + + b) cause the whole of any work that you distribute or publish, that + in whole or in part contains the Program or any part thereof, either + with or without modifications, to be licensed at no charge to all + third parties under the terms of this General Public License (except + that you may choose to grant warranty protection to some or all + third parties, at your option). + + c) If the modified program normally reads commands interactively when + run, you must cause it, when started running for such interactive use + in the simplest and most usual way, to print or display an + announcement including an appropriate copyright notice and a notice + that there is no warranty (or else, saying that you provide a + warranty) and that users may redistribute the program under these + conditions, and telling the user how to view a copy of this General + Public License. + + d) You may charge a fee for the physical act of transferring a + copy, and you may at your option offer warranty protection in + exchange for a fee. + +Mere aggregation of another independent work with the Program (or its +derivative) on a volume of a storage or distribution medium does not bring +the other work under the scope of these terms. + + 3. You may copy and distribute the Program (or a portion or derivative of +it, under Paragraph 2) in object code or executable form under the terms of +Paragraphs 1 and 2 above provided that you also do one of the following: + + a) accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of + Paragraphs 1 and 2 above; or, + + b) accompany it with a written offer, valid for at least three + years, to give any third party free (except for a nominal charge + for the cost of distribution) a complete machine-readable copy of the + corresponding source code, to be distributed under the terms of + Paragraphs 1 and 2 above; or, + + c) accompany it with the information you received as to where the + corresponding source code may be obtained. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form alone.) + +Source code for a work means the preferred form of the work for making +modifications to it. For an executable file, complete source code means +all the source code for all modules it contains; but, as a special +exception, it need not include source code for modules which are standard +libraries that accompany the operating system on which the executable +file runs, or for standard header files or definitions files that +accompany that operating system. + + 4. You may not copy, modify, sublicense, distribute or transfer the +Program except as expressly provided under this General Public License. +Any attempt otherwise to copy, modify, sublicense, distribute or transfer +the Program is void, and will automatically terminate your rights to use +the Program under this License. However, parties who have received +copies, or rights to use copies, from you under this General Public +License will not have their licenses terminated so long as such parties +remain in full compliance. + + 5. By copying, distributing or modifying the Program (or any work based +on the Program) you indicate your acceptance of this license to do so, +and all its terms and conditions. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the original +licensor to copy, distribute or modify the Program subject to these +terms and conditions. You may not impose any further restrictions on the +recipients' exercise of the rights granted herein. + + 7. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of the license which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +the license, you may choose any version ever published by the Free Software +Foundation. + + 8. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to humanity, the best way to achieve this is to make it +free software which everyone can redistribute and change under these +terms. + + To do so, attach the following notices to the program. It is safest to +attach them to the start of each source file to most effectively convey +the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19xx name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the +appropriate parts of the General Public License. Of course, the +commands you use may be called something other than `show w' and `show +c'; they could even be mouse-clicks or menu items--whatever suits your +program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + program `Gnomovision' (a program to direct compilers to make passes + at assemblers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/bfd/ChangeLog b/bfd/ChangeLog new file mode 100644 index 00000000000..e9d10f601d6 --- /dev/null +++ b/bfd/ChangeLog @@ -0,0 +1,314 @@ +Tue Mar 5 01:47:57 1991 John Gilmore (gnu at cygint.cygnus.com) + + * coff-code.h (bfd_coff_swap_sym, bfd_coff_swap_aux, + bfd_coff_swap_lineno): Export the routines that byte-swap COFF + symbol tables if necessary when reading them in, so gdb can use + them. Add "bfd_coff_" to the names so they won't conflict with + names in calling programs. FIXME-soon: if coff-code.h is + included in two BFD modules, this will cause duplicate + definitions; the routines should be exported to a separate, + common, module (probably along with a mess of other ones). + +Sat Mar 2 12:11:26 1991 John Gilmore (gnu at cygint.cygnus.com) + + Improve modtime support. + + * bfd.h: Add boolean mtime_set, and declare bfd_get_mtime. + Remove #define for bfd_get_mtime. Remove gratuitous comment. + * bfd.c (bfd_get_mtime): New fn, caches mtime, gets if not cached. + BUG: archive members still do not get correct mod times. + + Improve floating point support for core files. + + * sunos.c (struct core): Change void *fpa_dummy to double fp_stuff. + (sunos4_core_file_p): Create a second registers section in the + core file, called ".reg2", for the float registers. + +Thu Feb 14 15:49:06 1991 Gumby Vinayak Wallace (gumby at cygint.cygnus.com) + + * many changes to improve archive handling; found a logic flaw in + bfd_check_format which only just happened to work by cooncidence. + +Thu Feb 14 07:53:16 1991 Steve Chamberlain (steve at cygint.cygnus.com) + + * bfd.c (bfd_perform_relocation): fixed to use output_offsets + correctly. + + * bfd.h: changed type of udata in asymbol to void *, like it + should be. Added bfd_reloc_dangerous enum member. + + * coff-code.h: Fixed it so that internally generated symbols get + their values relocated correctly in all cases. Removed calls to + xmalloc. + + * icoff.c: Not understanding the destination symbol of a reloc is + not a failure any more, just 'dangerous'. This allows linking of + b.out and coff images. + + * sunos.c: Cleaned up the way that ZMAGIC section sizes are + calculated. + + +Tue Feb 12 13:25:46 1991 Steve Chamberlain (steve at cygint.cygnus.com) + + * sunos.c (translate_to_native_sym_flags): fixed + sym_pointer->n_value so that symbols on the way out get their + section relative values calculated correctly. + + * coff-code.h (mangle_symbols): fixed problem where tags were not + being relocated for structs, enums, unions. Also various lints. + +Mon Feb 11 19:52:26 1991 Gumby Vinayak Wallace (gumby at cygint.cygnus.com) + + * archive.c (get_elt_at_filepos): system_call_error returned + incorrectly. + +Sun Feb 10 23:18:40 1991 Gumby Vinayak Wallace (gumby at cygint.cygnus.com) + + * Resolve the use of no_error and system_call_error. + The bfd library itself now will never set bfd_error to + no_error. + + The code still needs to be combed to make sure all the error + codes are correct. I suspect they are not always set correctly. + + * The names of all the messages have _ prepended because the sun + bundled compiler can't distinguish from a macro which takes an + argument and the same identifier in a non-macro context. + + * The reason for the above being that entry points which used to + be trampoline functions are now just macros which expand to a + direct call through the bfd's xfer vector. + + * (../include/intel-coff.h) F_AR32WR: fix this constant. Why + must gas have its own version of everything (the gas version + had the correct value) + +Tue Feb 5 11:46:53 1991 Steve Chamberlain (steve at cygint.cygnus.com) + + * b.out.c: Added patches supplied by chrisb@mipon2.intel.com to + properly support i960 architecture and output correct reloc stuff. + + * bfd.h: added prototype for bfd_printable_arch_mach, added + BFD_FAIL + + * coff-code.h: Applied patches from chrisb to support i960 + architecture, zero relocs and swap them correcly and conditionally + compiled the timestamp. + + * sunos.c: Made the default section alignment 2^3 so that doubles + are done properly. Fixed the same reloc bug that was in b.out.c + + * sysdep.h: Now compiles on a Posix box + +Wed Jan 30 21:36:26 1991 John Gilmore (gnu at cygint.cygnus.com) + + * icoff.c: Fix comment on big-endian version. + * coff-code.h: Make HAS_RELOC really work (it's backwards from + F_RELFLG). Set F_AR32WR in output files if little endian + architecture. + +Tue Jan 29 20:56:10 PST 1991 steve@cygnus.com + + * archures.c fixed =/== typo + + * sunos.c added architecture stuff for output. Fixed + bug where files where vma(data) != size(text) + were processed wrong. + + * coff-code.h added a lint cast + + * (../include/a.out.sun4.h) fixed it so zmagic + worked + +Mon Jan 28 19:15:29 PST 1991 steve@cygnus.com + + * archive.c removed loads of includes, and fixed bug where string + table didn't have a null at the end. + + * bfd.c fixed includes, added symbols argument to + canonicalize_reloc entry point. + + * libbfd.c fixed includes and added some lint patches. + + * targets.c added both sorts of intel coff. + + * b.out.c fixed included, changed was the canonical + relocs were done. + + * icoff.c added support for callj and big and little + enidian tables. + + * opncls.c added chmod+xing for files with EXEC_P set. + + * sunos.c fixed includes. Changed default section + alignement to words. Fixed relocation stuff to work with + new scheme + + * bfd.h various new types added, prototype for new + reloc calls, changed bfd->iostream to a void * + to including files don't need stdio.h. + + * libcoff.h added conversion table to tie relocs to + canonical symbols + + * sysdep.h created + + * coff-code.h fixed includes. Added code to support + big and little endian formats. Various lints. Better + processing of symbols. Changed reloc stuff to new + order + + * libbfd.h fixed includes + + +Mon Jan 21 11:53:51 PST 1991 steve@cygnus.com + + * bfd.h changed name of alignment entry in sec_struct to + alignment_power, because of conflicting uses within bfd. + Now it should be obvious that it's a 2**n alignment + specifier. Removed start_pad, end_alignment, block, minsize, + output_file_alignment, subsection_alignment and original_vma fields. + Added align_power() macro. Fixed bfd_section_alignment + acessor macros. Added bfd_symbol_same_target macro. + + * b.out.c (b_out_write_object_contents) fixed to use + new alignment member. Fixed (callj_callback) to use section + relative symbols properly. + + * sunos.c (sunos4_object_p) fixed to use new alignment_power. + Fixed (translate_from_native_sym_flags) to correctly make + symbols section relative. + + * bfd.c (bfd_errmsg) fixed various enum cast problems. + (bfd_make_section) took out initialization of obsolete members. + (bfd_print_symbol_vandf) added + + * opncls.c (bfd_create) created. + + * coff-code.h (coff_new_section_hook) took away refs + to obsolete members. (make_a_section_from_file) added + conversion between alignment types. (coff_symbol_from) + added. (coff_count_linenumbers) only counts linenumbers + if symbol is of coff-type. (coff_mangle_symbols) only + heavily mangles symbols if symbol is coff-type. + (coff_write_symbols) various lints. (coff_write_object_contents) + various lints and modification for alignment conversion. + (coff_slurp_relocs) fixed for use with new asection shape. + +Sat Jan 19 16:10:42 PST 1991 steve@cygnus.com + + * archive.c lots of lint + + * b.out.c added callj relocation support, upgrated reloc howto. + Fixed so that asymbol and reloc records are output + correctly. + + * bfd.c lots of lint, support for new bfd entry point + bfd_print_symbol. + + * bfd.h changed definition of asymbol to contain pointer to + owning bfd, removed target dependencies. + + * cache.c took out print statements, put in BFD_ASSERT calls. + + * coff-code.h various lints, corrected linenumber output + functionality. Added support for new style asymbols and + bfd_print_symbol. Fixed so that asymbol and + reloc records are handled correctly. Added timestamp. + + * icoff.c Added support for new howto shape. + + * liba.out.h Added support for new asymbol shape + + * libbfd.c various lints + + * libbfd.h various lints + + * libcoff.h added support for new asymbol shape. + + * sunos.c various lints. Added support for new asymbol shape + and bfd_print_symbol. + +Wed Jan 16 21:38:09 PST 1991 steve@cygnus.com + + * b.out.c removed prototype of sunos4_ennativate_symtab, lots of + pointer lint. Added support for callj relocation. Fixed bug where + the last 32 bytes of the text section were overwritten by data. Fixed bug + where archives of b.out didn't work due bfd_slurp_extended_name_table + returning false. + + * sunos.c added support for n_other field. Braced the howto table so + that it won't be affected by any lengthing of the howto struct typedef. + Various lints + + * bfd.h added support for n_other field, added special_function + reloc type, modified bfd_perform_relocation prototype. Added bfd_h_get_x + macros. + + * bfd.c upgraded bfd_perform_relocation, various lints. + +Wed Jan 16 01:55:53 1991 John Gilmore (gnu at rtl) + + * ChangeLog: Started ChangeLog for BFD. + * ToDo: Create file for suggestions. + + * Makefile: Support easy loading into Saber C. + Add dependencies for icoff.o and bcs88kcoff.o. + Rename coff.c to coff-code.h. Change callers. + + * bfd.c (bfd_check_format): Allow the check_format routines + to return the desired target vector, rather than just a Boolean. + bfd.h (bfd_check_format): Change function pointer return type. + archive.c (bfd_generic_archive_p): change callee. + b.out.c (b_out_little_object_p, b_out_big_object_p, + b_out_real_object_p): change callee. + libbfd.c (_bfd_dummy_target): Dummy routine replacing bfd_false + in check_format transfer vectors that need a filler. + libbfd.h (bfd_generic_archive_p, _bfd_dummy_target): Fix decls. + bcs88kcoff.c: change callee. + coff-code.h (coff_real_object_p, coff_big_object_p): change callee. + icoff.c: change callee. + sunos.c (sunos4_object_p, sunos4_core_file_p): change callee. + + * libbfd.c (zalloc): It should actually zero the storage! + This was commented out for some reason. + + * libbfd.h: Add malloc, xmalloc, memcpy, and fatal decls. + This is so callers can avoid which doesn't exist + on older systems. + + * bfd.c (map_over_sections): Add debugging code, since I + noticed the section count for sunos core files was bad, but only + GDB had detected the problem. + (bfd_set_section_lineno_size, bfd_set_section_linenos, + bfd_get_section_linenos): Remove obsolete functions. + (bfd_apply_relocations): Use longs, not ints, for the math. + + * bfd.h: Declare enum boolean and struct bfd_target as well + as typedefs for them. Remove obsolete + bfd_get_section_lineno_size. + + * cache.c: Make the "fdopen" support work. Keep better track + of how many files are open. Centralize the opening of files + and be sure bfd_open[rw] actually try to open the file. Evade + linked list initialization problems. + + * b.out.c, coff-code.h, opncls.c, sunos.c: lint. + + * coff-code.h (coff_slurp_symbol_table): Null-terminate symtab names. + + * cplus-dem.c: Delete file, since it is not part of BFD. + + * opncls.c (bfd_openr): Eliminate misplaced #if 0 code. + (bfd_openr, bfd_openw): Actually open the file, give error now. + + * sunos.c (sunos4_core_file_p): Set section count. + (sunos4_set_section_linenos, stab_names, fprint_name): Eliminiate + obsolete definitions. + (_write_symbol_table): Initialize counter. + (foop): Eliminate debugging code. + + + + diff --git a/bfd/Makefile b/bfd/Makefile new file mode 100755 index 00000000000..54dfd90732b --- /dev/null +++ b/bfd/Makefile @@ -0,0 +1,158 @@ +# +# Copyright (C) 1990, 1991 Free Software Foundation, Inc. +# +# This file is part of BFD, the Binary File Diddler. +# +# BFD 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 1, or (at your option) +# any later version. +# +# BFD 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 BFD; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +# $Id$ + +srcdir=. + +RANLIB = ranlib +CSWITCHES = -g # -Wall +#CDEFINES = # -DHOST_SYS=AIX_SYS # -DCOFF_TIMESTAMP -DANSI_LIBRARIES +INCDIR = ${srcdir}/../../include-cygnus +CSEARCH = -I$(INCDIR) + +TARG = libbfd.a +CFLAGS = $(CDEFINES) $(CSEARCH) $(CSWITCHES) -DINTEL960VERSION + + +BFD_LIBS = libbfd.o opncls.o bfd.o archive.o targets.o cache.o archures.o + +BFD_BACKENDS = sunos.o icoff.o b.out.o # srec.o # bcs88kcoff.o + +BFD_H=$(INCDIR)/bfd.h +SYSDEP_H=$(INCDIR)/sysdep.h + +# C source files that correspond to .o's. +CFILES = libbfd.c opncls.c bfd.c archive.c targets.c cache.c archures.c \ + sunos.c icoff.c b.out.c # srec.c # bcs88kcoff.c + +all: $(TARG) + +POINTOS = $(BFD_LIBS) $(BFD_BACKENDS) + +$(TARG): $(POINTOS) + rm -f $(TARG) + ar clq $(TARG) $(BFD_LIBS) $(BFD_BACKENDS) + ranlib $(TARG) + +tags etags: TAGS + +TAGS: .force + etags $(INCDIR)/*.h *.h *.c + +clean: + rm -f $(BFD_LIBS) $(BFD_BACKENDS) *~ core libbfd.a + +clobber realclean: clean + rm -f libbfd.a TAGS + +$(BFD_LIBS) $(BFD_BACKENDS): libbfd.h $(BFD_H) + +saber: + #suppress 65 on bfd_map_over_sections + #suppress 66 on bfd_map_over_sections + #suppress 67 on bfd_map_over_sections + #suppress 68 on bfd_map_over_sections + #suppress 69 on bfd_map_over_sections + #suppress 70 on bfd_map_over_sections + #suppress 110 in bfd_map_over_sections + #suppress 112 in bfd_map_over_sections + #suppress 530 + #suppress 590 in swap_exec_header + #suppress 590 in _bfd_dummy_core_file_matches_executable_p + #suppress 590 in bfd_dont_truncate_arname + #suppress 590 on ignore + #suppress 590 on abfd + #setopt load_flags $(CFLAGS) + #load $(CFILES) + +archive.o : archive.c libbfd.h $(BFD_H) $(SYSDEP_H) +archures.o : archures.c $(BFD_H) $(SYSDEP_H) archures.h +b.out.o : b.out.c libbfd.h $(BFD_H) $(SYSDEP_H) liba.out.h archures.h +bcs88kcoff.o : bcs88kcoff.c libbfd.h $(BFD_H) $(SYSDEP_H) libcoff.h coff-code.h archures.h +bfd.o : bfd.c libbfd.h $(BFD_H) $(SYSDEP_H) +cache.o : cache.c libbfd.h $(BFD_H) $(SYSDEP_H) +coff.o : coff.c +cplus-dem.o : cplus-dem.c +filemode.o : filemode.c +icoff.o : icoff.c libbfd.h $(BFD_H) $(SYSDEP_H) libcoff.h coff-code.h archures.h +libbfd.o : libbfd.c libbfd.h $(BFD_H) $(SYSDEP_H) +misc.o : misc.c +opncls.o : opncls.c libbfd.h $(BFD_H) $(SYSDEP_H) +sunos.o : sunos.c libbfd.h $(BFD_H) $(SYSDEP_H) liba.out.h +targets.o : targets.c libbfd.h $(BFD_H) $(SYSDEP_H) + +#----------------------------------------------------------------------------- +# 'STANDARD' GNU/960 TARGETS BELOW THIS POINT +# +# 'VERSION' file must be present and contain a string of the form "x.y" +#----------------------------------------------------------------------------- + +ver960.c: FORCE + rm -f ver960.c + echo "char ${TARG}_ver[]= \"${TARG} `cat VERSION`, `date`\";" > ver960.c + + +# This target should be invoked before building a new release. +# 'VERSION' file must be present and contain a string of the form "x.y" +# +roll: + @V=`cat VERSION` ; \ + MAJ=`sed 's/\..*//' VERSION` ; \ + MIN=`sed 's/.*\.//' VERSION` ; \ + V=$$MAJ.`expr $$MIN + 1` ; \ + rm -f VERSION ; \ + echo $$V >VERSION ; \ + echo Version $$V + +# Dummy target to force execution of dependent targets. +# +.force: +FORCE: + +# 'G960BASE' will be defined at invocation +install: + make ${TARG} OPT=-O + +# Target to uncomment host-specific lines in this makefile. Such lines must +# have the following string beginning in column 1: #____# +# Original Makefile is backed up as 'Makefile.old'. +# +# Invoke with: make make HOST=xxx +# +make: + -@if test $(HOST)x = x ; then \ + echo 'Specify "make make HOST=???"'; \ + exit 1; \ + fi ; \ + grep -s "^#The next line was generated by 'make make'" Makefile; \ + if test $$? = 0 ; then \ + echo "Makefile has already been processed with 'make make'";\ + exit 1; \ + fi ; \ + mv -f Makefile Makefile.old; \ + echo "#The next line was generated by 'make make'" >Makefile ; \ + echo "HOST=$(HOST)" >>Makefile ; \ + echo >>Makefile ; \ + sed "s/^#__$(HOST)__#//" < Makefile.old >>Makefile + +Makefile: ../common/Makefile + mv Makefile Makefile.backup + cp ../common/Makefile . + $(MAKE) "HOST=$(HOST)" make diff --git a/bfd/TODO b/bfd/TODO new file mode 100644 index 00000000000..45cf905c933 --- /dev/null +++ b/bfd/TODO @@ -0,0 +1,49 @@ +Things that still need to be handled: -*- Text -*- + + o - check all the swapping code. + o - change the memory usage to reflect the message which follows the + page break. + o - implement bfd_abort, which should close the bfd but not alter the + filesystem. + o - remove the following obsolete functions: + bfd_symbol_value + bfd_symbol_name + bfd_get_first_symbol + bfd_get_next_symbol + bfd_classify_symbol + bfd_symbol_hasclass + o - update the bfd doc; write a how-to-write-a-backend doc. + o - change reloc handling as per Steve's suggestion. + + +Changing the way bfd uses memory. The new convention is simple: + + o - bfd will never write into user-supplied memory, nor attempt to + free it. + o - closing a bfd may reclaim all bfd-allocated memory associated + with that bfd. + - - bfd_target_list will be the one exception; you must reclaim the + returned vector yourself. + +Interface implications are minor (get_symcount_upper_bound will go +away; bfd_cannicalize_symtab will allocate its own memory, etc). + +Certain operations consume a lot of memory; for them manual +reclaimation is available: + + o - bfd_canonicalize_symtab will return a pointer to a + null-terminated vector of symbols. Subsequent calls may or may + not return the same pointer. + bfd_canonicalize_relocs will do the same; returning a pointer to + an array of arelocs. Calling this function will read symbols in + too. + + o - bfd_reclaim_relocs will free the memory used by these relocs. + the symbols will be untouched. + bfd_reclaim_symtab (ne bfd_reclaim_symbol_table) will free the + memory allocated by canonialize_symtab. + Since relocations point to symbols, any relocations obtained by a + call to bfd_canonicalize_relocs will be reclaimed as well. + + o - if you don't call the reclaim_ functions, the memory will be + reclaimed at bfd_close time. diff --git a/bfd/aout.c b/bfd/aout.c new file mode 100755 index 00000000000..f857897819e --- /dev/null +++ b/bfd/aout.c @@ -0,0 +1,1904 @@ +/*** bfd backend for sunos binaries */ + +/* Copyright (C) 1990, 1991 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Diddler. + +BFD 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 1, or (at your option) +any later version. + +BFD 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 BFD; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* $Id$ + * $Log$ + * Revision 1.1 1991/03/21 21:11:23 gumby + * Initial revision + * + * Revision 1.2 1991/03/15 18:16:52 rich + * *** empty log message *** + * + * Revision 1.12 1991/03/10 19:11:41 rich + * Modified Files: + * bfd.c coff-code.h libbfd.c libbfd.h srec.c sunos.c + * + * Working bugs out of coff support. + * + * Revision 1.11 1991/03/09 03:40:04 rich + * Modified Files: + * Makefile b.out.c liba.out.h libbfd.c sunos.c sysdep.h + * + * Changes dictated by porting binutils. + * + * Revision 1.10 1991/03/08 07:52:02 sac + * Reinstalled things which went away after latest merge from Intel. + * + * Fixed a couple of problems in symbol handling too. + * + * Revision 1.9 1991/03/08 04:18:16 rich + * *** empty log message *** + * + * Revision 1.8 1991/03/07 21:57:26 sac + * Moved type info out of the asymbol into the private space. + * Cleaned up C++ stuff + * + * Revision 1.7 1991/03/06 21:49:02 sac + * Modified bfd_find_filename to return name of function too. + * + * Revision 1.6 1991/03/06 02:19:36 sac + * Moved howto table, added support for constructor sections and provided + * sunos4_find_nearest_line + * + * Revision 1.5 1991/03/05 16:25:44 sac + * Modified howto vector to include inplace and mask fields. + * + */ + +#define TARGET_BYTE_ORDER_BIG_P 1 +#define TARGET TARGET_SPARC + +#include "sysdep.h" +#include "bfd.h" +#include "libbfd.h" +#include + + +/*SUPPRESS558*/ +/*SUPPRESS529*/ + + + + +typedef void generic_symbol_type; +/* These values are correct for the SPARC. I dunno about anything else */ +#define PAGE_SIZE 0x02000 +#define SEGMENT_SIZE PAGE_SIZE +#define TEXT_START_ADDR PAGE_SIZE +#include "a.out.gnu.h" +#include "stab.gnu.h" +#include "ar.h" +#include "liba.out.h" /* BFD a.out internal data structures */ + +#include "a.out.sun4.h" + +#define CTOR_TABLE_RELOC_IDX 2 +static reloc_howto_type howto_table[] = +{ + /* type rs size bsz pcrel bitpos abs ovrf sf name partial inplace mask*/ +{ (unsigned int) RELOC_8, 0, 0, 8, false, 0, true, true,0,"8", false, 0x000000ff}, +{ (unsigned int) RELOC_16, 0, 1, 16, false, 0, true, true,0,"16", false, 0x0000ffff}, +{ (unsigned int) RELOC_32, 0, 2, 32, false, 0, true, true,0,"32", false, 0xffffffff}, +{ (unsigned int) RELOC_DISP8, 0, 0, 8, true, 0, false, true,0,"DISP8", false, 0x000000ff}, +{ (unsigned int) RELOC_DISP16, 0, 1, 16, true, 0, false, true,0,"DISP16", false, 0x0000ffff}, +{ (unsigned int) RELOC_DISP32, 0, 2, 32, true, 0, false, true,0,"DISP32", false, 0xffffffff}, +{ (unsigned int) RELOC_WDISP30,2, 2, 30, true, 0, false, true,0,"WDISP30", false, 0x3fffffff}, +{ (unsigned int) RELOC_WDISP22,2, 2, 22, true, 0, false, true,0,"WDISP22", false, 0x003fffff}, +{ (unsigned int) RELOC_HI22, 10, 2, 22, false, 0, false, true,0,"HI22", false, 0x003fffff}, +{ (unsigned int) RELOC_22, 0, 2, 22, false, 0, false, true,0,"22", false, 0x003fffff}, +{ (unsigned int) RELOC_13, 0, 2, 13, false, 0, false, true,0,"13", false, 0x00001fff}, +{ (unsigned int) RELOC_LO10, 0, 2, 10, false, 0, false, true,0,"LO10", false, 0x000003ff}, +{ (unsigned int) RELOC_SFA_BASE,0, 2, 32, false, 0, false, true,0,"SFA_BASE", false, 0xffffffff}, +{ (unsigned int) RELOC_SFA_OFF13,0,2, 32, false, 0, false, true,0,"SFA_OFF13",false, 0xffffffff}, +{ (unsigned int) RELOC_BASE10, 0, 2, 16, false, 0, false, true,0,"BASE10", false, 0x0000ffff}, +{ (unsigned int) RELOC_BASE13, 0, 2, 13, false, 0, false, true,0,"BASE13", false, 0x00001fff}, +{ (unsigned int) RELOC_BASE22, 0, 2, 0, false, 0, false, true,0,"BASE22", false, 0x00000000}, +{ (unsigned int) RELOC_PC10, 0, 2, 10, false, 0, false, true,0,"PC10", false, 0x000003ff}, +{ (unsigned int) RELOC_PC22, 0, 2, 22, false, 0, false, true,0,"PC22", false, 0x003fffff}, +{ (unsigned int) RELOC_JMP_TBL,0, 2, 32, false, 0, false, true,0,"JMP_TBL", false, 0xffffffff}, +{ (unsigned int) RELOC_SEGOFF16,0, 2, 0, false, 0, false, true,0,"SEGOFF16", false, 0x00000000}, +{ (unsigned int) RELOC_GLOB_DAT,0, 2, 0, false, 0, false, true,0,"GLOB_DAT", false, 0x00000000}, +{ (unsigned int) RELOC_JMP_SLOT,0, 2, 0, false, 0, false, true,0,"JMP_SLOT", false, 0x00000000}, +{ (unsigned int) RELOC_RELATIVE,0, 2, 0, false, 0, false, true,0,"RELATIVE", false, 0x00000000}, +{ (unsigned int) RELOC_JUMPTARG,2, 13, 16, true, 0, false, true,0,"JUMPTARG", false, 0x0000ffff}, +{ (unsigned int) RELOC_CONST, 0, 13, 16, false, 0, false, true,0,"CONST", false, 0x0000ffff}, +{ (unsigned int) RELOC_CONSTH, 16, 13, 16, false, 0, false, true,0,"CONSTH", false, 0x0000ffff}, +}; + +/** a.out files */ + +PROTO (static void, swap_exec_header, (bfd *abfd, struct exec *execp)); +PROTO (void , sunos4_write_syms, ()); +PROTO (static boolean,sunos4_squirt_out_relocs,(bfd *abfd, asection *section)); + +/* Steve wants some way to frob this stuff from Saber while he's debugging + ld, so we have these funny shadow functions */ +/* ZMAGIC's start at 0 (making the exec part of the text section), + other formats start after the exec +*/ +unsigned int n_txtoff(ptr) +struct exec *ptr; +{return N_MAGIC(*ptr)== ZMAGIC ? 0: sizeof(struct exec);} + +unsigned int n_datoff(ptr) +struct exec *ptr; +{return n_txtoff(ptr) + ptr->a_text;} + +unsigned int n_treloff(ptr) +struct exec *ptr; +{return n_datoff(ptr) + ptr->a_data;} + +unsigned int n_dreloff(ptr) +struct exec *ptr; +{return n_treloff(ptr) + ptr->a_trsize;} + +unsigned int n_symoff(ptr) +struct exec *ptr; +{return n_dreloff(ptr) + ptr->a_drsize;} + +unsigned int n_stroff(ptr) +struct exec *ptr; +{return n_symoff(ptr) + ptr->a_syms;} + +unsigned int n_badmag(ptr) + struct exec *ptr; +{ + switch (N_MAGIC(*ptr)) { + case OMAGIC: case NMAGIC: case ZMAGIC: return 0; + default: return 1; + } +} + + +bfd_target * +sunos4_object_p (abfd) + bfd *abfd; +{ + unsigned long magic; + struct exec anexec; /* save consing when you don't have to. */ + struct exec *execp = &anexec; + void *rawptr; + + bfd_error = system_call_error; + + if (bfd_read ((void *)&magic, 1, sizeof (magic), abfd) != sizeof (magic)) + return 0; + magic = bfd_h_getlong (abfd, &magic); + + /* Baroque syntax to mask deficiencies of the Sun compiler */ + /* if (N_BADMAG (*((struct exec *) &magic))) return 0; */ + if (n_badmag ((struct exec *) &magic)) return 0; + + if (bfd_seek (abfd, 0L, SEEK_SET) < 0) return 0; + + if (bfd_read ((void *) execp, 1, sizeof (struct exec), abfd) + != sizeof (struct exec)) { + bfd_error = wrong_format; + return 0; + } + + /* Use an intermediate variable for clarity */ + rawptr = (void *) zalloc (sizeof (struct sunexdata) + sizeof (struct exec)); + + if (rawptr == NULL) { + bfd_error = no_memory; + return 0; + } + + abfd->tdata =(void *)( (struct sunexdata *) rawptr); + exec_hdr (abfd) = + (struct exec *) ((char *)rawptr + sizeof (struct sunexdata)); + + swap_exec_header (abfd, execp); + memcpy (exec_hdr (abfd), execp, sizeof (struct exec)); + + /* Set the file flags */ + abfd->flags = NO_FLAGS; + if (execp->a_drsize || execp->a_trsize) + abfd->flags |= HAS_RELOC; + if (execp->a_entry) + abfd->flags |= EXEC_P; + if (execp->a_syms) + abfd->flags |= HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS; + + + if (N_MAGIC (anexec) == ZMAGIC) abfd->flags |= D_PAGED; + if (N_MAGIC (anexec) == NMAGIC) abfd->flags |= WP_TEXT; + + /* Determine the architecture and machine type of the object file. */ + abfd->obj_arch = bfd_arch_unknown; /* Default values */ + abfd->obj_machine = 0; + switch (N_MACHTYPE (anexec)) { + + case M_UNKNOWN: + break; + + case M_68010: + abfd->obj_arch = bfd_arch_m68k; + abfd->obj_machine = 68010; + break; + + case M_68020: + abfd->obj_arch = bfd_arch_m68k; + abfd->obj_machine = 68020; + break; + + case M_SPARC: + abfd->obj_arch = bfd_arch_sparc; + break; + + case M_386: + abfd->obj_arch = bfd_arch_i386; + break; + + case M_29K: + abfd->obj_arch = bfd_arch_a29k; + break; + + default: + abfd->obj_arch = bfd_arch_obscure; + break; + } + + bfd_get_start_address (abfd) = execp->a_entry; + + /* Remember the positions of the string table and symbol table. */ + obj_str_filepos (abfd) = n_stroff (&anexec); + obj_sym_filepos (abfd) = n_symoff (&anexec); + + /* create the sections. This is raunchy, but bfd_close wants to reclaim + them */ + obj_textsec (abfd) = (asection *)NULL; + obj_datasec (abfd) = (asection *)NULL; + obj_bsssec (abfd) = (asection *)NULL; + obj_aout_symbols(abfd) = (aout_symbol_type *)NULL; + (void)bfd_make_section(abfd, ".text"); + (void)bfd_make_section(abfd, ".data"); + (void)bfd_make_section(abfd, ".bss"); + + obj_datasec (abfd)->size = execp->a_data; + obj_bsssec (abfd)->size = execp->a_bss; + obj_textsec (abfd)->size = execp->a_text; + obj_datasec (abfd)->vma = N_DATADDR(anexec); + obj_bsssec (abfd)->vma = N_BSSADDR(anexec); + obj_textsec (abfd)->vma = N_TXTADDR(anexec); + + obj_textsec (abfd)->filepos = n_txtoff(&anexec); + obj_datasec (abfd)->filepos = n_datoff(&anexec); + + obj_textsec (abfd)->rel_filepos = n_treloff(&anexec); + obj_datasec (abfd)->rel_filepos = n_dreloff(&anexec); + + obj_textsec (abfd)->flags = + (execp->a_trsize != 0 ? + (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_HAS_CONTENTS) : + (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS)); + obj_datasec (abfd)->flags = + (execp->a_drsize != 0 ? + (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_HAS_CONTENTS) : + (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS)); + obj_bsssec (abfd)->flags = SEC_ALLOC; + + abfd->sections = obj_textsec (abfd); + obj_textsec (abfd)->next = obj_datasec (abfd); + obj_datasec (abfd)->next = obj_bsssec (abfd); + return abfd->xvec; +} + + +boolean +sunos4_mkobject (abfd) + bfd *abfd; +{ + char *rawptr; + + bfd_error = system_call_error; + + /* Use an intermediate variable for clarity */ + rawptr = zalloc (sizeof (struct sunexdata) + sizeof (struct exec)); + + if (rawptr == NULL) { + bfd_error = no_memory; + return false; + } + + abfd->tdata = (void *)((struct sunexdata *) rawptr); + exec_hdr (abfd) = (struct exec *) (rawptr + sizeof (struct sunexdata)); + + /* For simplicity's sake we just make all the sections right here. */ + + obj_textsec (abfd) = (asection *)NULL; + obj_datasec (abfd) = (asection *)NULL; + obj_bsssec (abfd) = (asection *)NULL; + bfd_make_section (abfd, ".text"); + bfd_make_section (abfd, ".data"); + bfd_make_section (abfd, ".bss"); + + return true; +} + +/* Keep track of machine architecture and machine type for a.out's. + Return the machine_type for a particular arch&machine, or M_UNKNOWN + if that exact arch&machine can't be represented in a.out format. + + If the architecture is understood, machine type 0 (default) should + always be understood. */ + +static enum machine_type +aout_machine_type (arch, machine) + enum bfd_architecture arch; + unsigned long machine; +{ + enum machine_type arch_flags; + + arch_flags = M_UNKNOWN; + + switch (arch) { + case bfd_arch_sparc: + if (machine == 0) arch_flags = M_SPARC; + break; + + case bfd_arch_m68k: + switch (machine) { + case 0: arch_flags = M_UNKNOWN; break; + case 68000: arch_flags = M_UNKNOWN; break; + case 68010: arch_flags = M_68010; break; + case 68020: arch_flags = M_68020; break; + default: arch_flags = M_UNKNOWN; break; + } + break; + + case bfd_arch_i386: + if (machine == 0) arch_flags = M_386; + break; + + case bfd_arch_a29k: + if (machine == 0) arch_flags = M_29K; + break; + + default: + arch_flags = M_UNKNOWN; + break; + } + return arch_flags; +} + +boolean +sunos4_set_arch_mach (abfd, arch, machine) + bfd *abfd; + enum bfd_architecture arch; + unsigned long machine; +{ + abfd->obj_arch = arch; + abfd->obj_machine = machine; + if (arch != bfd_arch_unknown && + aout_machine_type (arch, machine) == M_UNKNOWN) + return false; /* We can't represent this type */ + return true; /* We're easy ... */ +} + +boolean +sunos4_write_object_contents (abfd) + bfd *abfd; +{ + int data_pad = 0; + struct exec *execp = exec_hdr (abfd); + + + + /* Magic number, maestro, please! */ + switch (bfd_get_architecture(abfd)) { + case bfd_arch_m68k: + switch (bfd_get_machine(abfd)) { + case 68010: + N_SET_MACHTYPE(*execp, M_68010); + break; + default: + case 68020: + N_SET_MACHTYPE(*execp, M_68020); + break; + } + break; + case bfd_arch_sparc: + N_SET_MACHTYPE(*execp, M_SPARC); + break; + case bfd_arch_i386: + N_SET_MACHTYPE(*execp, M_386); + break; + case bfd_arch_a29k: + N_SET_MACHTYPE(*execp, M_29K); + break; + default: + N_SET_MACHTYPE(*execp, M_UNKNOWN); + } + execp->a_text = obj_textsec (abfd)->size; + N_SET_MAGIC (*execp, OMAGIC); + if (abfd->flags & D_PAGED) { + execp->a_text = obj_textsec (abfd)->size + sizeof(struct exec); + N_SET_MAGIC (*execp, ZMAGIC); + } else if (abfd->flags & WP_TEXT) { + N_SET_MAGIC (*execp, NMAGIC); + } + N_SET_FLAGS (*execp, 0x1); /* copied from ld.c; who the hell knows? */ + + if (abfd->flags & D_PAGED) + { + data_pad = ((obj_datasec(abfd)->size + PAGE_SIZE -1) + & (- PAGE_SIZE)) - obj_datasec(abfd)->size; + + if (data_pad > obj_bsssec(abfd)->size) + execp->a_bss = 0; + else + execp->a_bss = obj_bsssec(abfd)->size - data_pad; + execp->a_data = obj_datasec(abfd)->size + data_pad; + + } + else { + execp->a_data = obj_datasec (abfd)->size; + execp->a_bss = obj_bsssec (abfd)->size; + } + + execp->a_syms = bfd_get_symcount (abfd) * sizeof (struct nlist); + execp->a_entry = bfd_get_start_address (abfd); + execp->a_trsize = ((obj_textsec (abfd)->reloc_count) * + sizeof (struct reloc_info_extended)); + execp->a_drsize = ((obj_datasec (abfd)->reloc_count) * + sizeof (struct reloc_info_extended));; + + swap_exec_header (abfd, execp); + + bfd_seek (abfd, 0L, SEEK_SET); + bfd_write ((void *) execp, 1, sizeof (struct exec), abfd); + + /* Now write out reloc info, followed by syms and strings */ + + if (bfd_get_symcount (abfd) != 0) + { + bfd_seek (abfd, + (long)(N_SYMOFF(*execp)), SEEK_SET); + + sunos4_write_syms (abfd); + + bfd_seek (abfd, (long)(N_TROFF(*execp)), SEEK_SET); + + if (!sunos4_squirt_out_relocs (abfd, obj_textsec (abfd))) return false; + bfd_seek (abfd, (long)(N_DROFF(*execp)), SEEK_SET); + + if (!sunos4_squirt_out_relocs (abfd, obj_datasec (abfd))) return false; + } + return true; +} + +static void +swap_exec_header (abfd, execp) +bfd *abfd; + struct exec *execp; +{ + if (bfd_header_twiddle_required(abfd)) { + /* execp->a_info = bfd_h_getlong (abfd, &execp->a_info); */ + *(unsigned long *) execp = + bfd_h_getlong (abfd, (unsigned long *) execp); + execp->a_text = bfd_h_getlong (abfd, &execp->a_text); + execp->a_data = bfd_h_getlong (abfd, &execp->a_data); + execp->a_bss = bfd_h_getlong (abfd, &execp->a_bss); + execp->a_syms = bfd_h_getlong (abfd, &execp->a_syms); + execp->a_entry = bfd_h_getlong (abfd, &execp->a_entry); + execp->a_trsize = bfd_h_getlong (abfd, &execp->a_trsize); + execp->a_drsize = bfd_h_getlong (abfd, &execp->a_drsize); + } +} /* swap_exec_header() */ + +/** core files */ + +#define CORE_MAGIC 0x080456 +#define CORE_NAMELEN 16 + +/* The core structure is taken from the Sun documentation. + Unfortunately, they don't document the FPA structure, or at least I + can't find it easily. Fortunately the core header contains its own + length. So this shouldn't cause problems, except for c_ucode, which + so far we don't use but is easy to find with a little arithmetic. */ + +/* But the reg structure can be gotten from the SPARC processor handbook. + This really should be in a GNU include file though so that gdb can use + the same info. */ +struct regs { + int r_psr; + int r_pc; + int r_npc; + int r_y; + int r_g1; + int r_g2; + int r_g3; + int r_g4; + int r_g5; + int r_g6; + int r_g7; + int r_o0; + int r_o1; + int r_o2; + int r_o3; + int r_o4; + int r_o5; + int r_o6; + int r_o7; +}; + +/* Taken from Sun documentation: */ + +struct core { + int c_magic; /* Corefile magic number */ + int c_len; /* Sizeof (struct core) */ + struct regs c_regs; /* General purpose registers */ + struct exec c_aouthdr; /* A.out header */ + int c_signo; /* Killing signal, if any */ + int c_tsize; /* Text size (bytes) */ + int c_dsize; /* Data size (bytes) */ + int c_ssize; /* Stack size (bytes) */ + char c_cmdname[CORE_NAMELEN + 1]; /* Command name */ + double fp_stuff[1]; /* external FPU state (size unknown by us) */ + /* The type "double" is critical here, for alignment. + SunOS declares a struct here, but the struct's + alignment is double since it contains doubles. */ + int c_ucode; /* Exception no. from u_code */ + /* (this member not accessible by name since we don't + portably know the size of fp_stuff.) */ +}; + +/* Supposedly the user stack grows downward from the bottom of kernel memory. + Presuming that this remains true, this definition will work. */ +#define USRSTACK (-(128*1024*1024)) + +PROTO (static void, swapcore, (bfd *abfd, struct core *core)); + +/* need this cast b/c ptr is really void * */ +#define core_hdr(bfd) (((struct suncordata *) (bfd->tdata))->hdr) +#define core_datasec(bfd) (((struct suncordata *) ((bfd)->tdata))->data_section) +#define core_stacksec(bfd) (((struct suncordata*)((bfd)->tdata))->stack_section) +#define core_regsec(bfd) (((struct suncordata *) ((bfd)->tdata))->reg_section) +#define core_regsec2(bfd) (((struct suncordata *) ((bfd)->tdata))->reg2_section) + +/* These are stored in the bfd's tdata */ +struct suncordata { + struct core *hdr; /* core file header */ + asection *data_section; + asection *stack_section; + asection *reg_section; + asection *reg2_section; +}; + +bfd_target * +sunos4_core_file_p (abfd) + bfd *abfd; +{ + /* includes redundent variables for code clarity */ + int core_size; + int core_mag; + struct core *core; + char *rawptr; + + bfd_error = system_call_error; + + if (bfd_read ((void *)&core_mag, 1, sizeof (int), abfd) != sizeof (int)) + return 0; + core_mag = bfd_h_getlong(abfd, &core_mag); + + if (core_mag != CORE_MAGIC) return 0; + + /* SunOS core headers can vary in length; second word is size; */ + if (bfd_read ((void *)&core_size, 1, sizeof (int), abfd) != sizeof (int)) + return 0; + core_size = bfd_h_getlong(abfd, &core_size); + + if (bfd_seek (abfd, 0L, SEEK_SET) < 0) return 0; + + rawptr = zalloc (core_size + sizeof (struct suncordata)); + if (rawptr == NULL) { + bfd_error = no_memory; + return 0; + } + + core = (struct core *) (rawptr + sizeof (struct suncordata)); + + if ((bfd_read ((void *) core, 1, core_size, abfd)) != core_size) { + bfd_error = system_call_error; + free ((void *)rawptr); + return 0; + } + + swapcore (abfd, core); + abfd->tdata = (void *)((struct suncordata *) rawptr); + core_hdr (abfd) = core; + + /* create the sections. This is raunchy, but bfd_close wants to reclaim + them */ + core_stacksec (abfd) = (asection *) zalloc (sizeof (asection)); + if (core_stacksec (abfd) == NULL) { + loser: + bfd_error = no_memory; + free ((void *)rawptr); + return 0; + } + core_datasec (abfd) = (asection *) zalloc (sizeof (asection)); + if (core_datasec (abfd) == NULL) { + loser1: + free ((void *)core_stacksec (abfd)); + goto loser; + } + core_regsec (abfd) = (asection *) zalloc (sizeof (asection)); + if (core_regsec (abfd) == NULL) { + loser2: + free ((void *)core_datasec (abfd)); + goto loser1; + } + core_regsec2 (abfd) = (asection *) zalloc (sizeof (asection)); + if (core_regsec2 (abfd) == NULL) { + free ((void *)core_regsec (abfd)); + goto loser2; + } + + core_stacksec (abfd)->name = ".stack"; + core_datasec (abfd)->name = ".data"; + core_regsec (abfd)->name = ".reg"; + core_regsec2 (abfd)->name = ".reg2"; + + core_stacksec (abfd)->flags = SEC_ALLOC + SEC_LOAD; + core_datasec (abfd)->flags = SEC_ALLOC + SEC_LOAD; + core_regsec (abfd)->flags = SEC_ALLOC; + core_regsec2 (abfd)->flags = SEC_ALLOC; + + core_stacksec (abfd)->size = core->c_ssize; + core_datasec (abfd)->size = core->c_dsize; + core_regsec (abfd)->size = (sizeof core->c_regs); + /* Float regs take up end of struct, except c_ucode. */ + core_regsec2 (abfd)->size = core_size - (sizeof core->c_ucode) - + (file_ptr)(((struct core *)0)->fp_stuff); + + core_stacksec (abfd)->vma = (USRSTACK - core->c_ssize); + core_datasec (abfd)->vma = N_DATADDR(core->c_aouthdr); + core_regsec (abfd)->vma = -1; + core_regsec2 (abfd)->vma = -1; + + core_stacksec (abfd)->filepos = core->c_len + core->c_dsize; + core_datasec (abfd)->filepos = core->c_len; + /* In file header: */ + core_regsec (abfd)->filepos = (file_ptr)(&((struct core *)0)->c_regs); + core_regsec2 (abfd)->filepos = (file_ptr)(((struct core *)0)->fp_stuff); + + /* Align to word at least */ + core_stacksec (abfd)->alignment_power = 2; + core_datasec (abfd)->alignment_power = 2; + core_regsec (abfd)->alignment_power = 2; + core_regsec2 (abfd)->alignment_power = 2; + + abfd->sections = core_stacksec (abfd); + core_stacksec (abfd)->next = core_datasec (abfd); + core_datasec (abfd)->next = core_regsec (abfd); + core_regsec (abfd)->next = core_regsec2 (abfd); + + abfd->section_count = 4; + + return abfd->xvec; +} + +char * +sunos4_core_file_failing_command (abfd) + bfd *abfd; +{ + return core_hdr (abfd)->c_cmdname; +} + +int +sunos4_core_file_failing_signal (abfd) + bfd *abfd; +{ + return core_hdr (abfd)->c_signo; +} + +boolean +sunos4_core_file_matches_executable_p (core_bfd, exec_bfd) + bfd *core_bfd, *exec_bfd; +{ + if (core_bfd->xvec != exec_bfd->xvec) { + bfd_error = system_call_error; + return false; + } + + return (bcmp (&core_hdr (core_bfd), &exec_hdr (exec_bfd), + sizeof (struct exec)) == 0) ? true : false; +} + +/* byte-swap core structure */ +static void +swapcore (abfd, core) +bfd *abfd; + struct core *core; +{ + if (bfd_header_twiddle_required(abfd)) { + core->c_magic = bfd_h_getlong (abfd, &core->c_magic); + core->c_len = bfd_h_getlong (abfd, &core->c_len); + /* regs */ + swap_exec_header (abfd, &(core->c_aouthdr)); + core->c_signo = bfd_h_getlong (abfd, &core->c_signo); + core->c_tsize = bfd_h_getlong (abfd, &core->c_tsize); + core->c_dsize = bfd_h_getlong (abfd, &core->c_dsize); + core->c_ssize = bfd_h_getlong (abfd, &core->c_ssize); + core->c_ucode = bfd_h_getlong (abfd, &core->c_ucode); + /* I don't understand how to swap an FP register */ + } +} + +/** exec and core file sections */ + +boolean +sunos4_new_section_hook (abfd, newsect) + bfd *abfd; + asection *newsect; +{ + /* align to double at least */ + newsect->alignment_power = 3; + + if (bfd_get_format (abfd) == bfd_object) { + if (obj_textsec(abfd) == NULL && !strcmp(newsect->name, ".text")) { + obj_textsec(abfd)= newsect; + return true; + } + + if (obj_datasec(abfd) == NULL && !strcmp(newsect->name, ".data")) { + obj_datasec(abfd) = newsect; + return true; + } + + if (obj_bsssec(abfd) == NULL && !strcmp(newsect->name, ".bss")) { + obj_bsssec(abfd) = newsect; + return true; + } + } + +#if 0 /* FIXME -- this is temporary for steve */ + bfd_error = invalid_operation; + + return false; +#endif + + /* We allow more than three sections internally */ + return true; +} + +boolean +sunos4_set_section_contents (abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + unsigned char *location; + file_ptr offset; + int count; +{ + if (abfd->output_has_begun == false) + { /* set by bfd.c handler */ + if ((obj_textsec (abfd) == NULL) || (obj_datasec (abfd) == NULL) + + /*|| + (obj_textsec (abfd)->size == 0) || (obj_datasec (abfd)->size= + 0)*/ + ) + { + bfd_error = invalid_operation; + return false; + } + + +#if 0 + if (abfd->flags & D_PAGED) + { + obj_textsec (abfd)->filepos = sizeof(struct exec); + obj_datasec(abfd)->filepos = obj_textsec (abfd)->size; + } + else +#endif +{ + obj_textsec (abfd)->filepos = sizeof(struct exec); + obj_datasec(abfd)->filepos = obj_textsec(abfd)->filepos + obj_textsec (abfd)->size; + + } + } + /* regardless, once we know what we're doing, we might as well get going */ + + bfd_seek (abfd, section->filepos + offset, SEEK_SET); + + if (count) { + return (bfd_write ((void *)location, 1, count, abfd) == count) ? true : false; + } + return false; +} +boolean +sunos4_get_section_contents (abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + void *location; + file_ptr offset; + int count; +{ + if (count) { + if (offset >= section->size) return false; + + bfd_seek (abfd, section->filepos + offset, SEEK_SET); + + return (bfd_read (location, 1, count, abfd) == count) ? true:false; + } + else return true; +} + + +/* Classify stabs symbols */ + + +#define sym_in_text_section(sym) \ + (((sym)->n_type & (N_ABS | N_TEXT | N_DATA | N_BSS))== N_TEXT) + +#define sym_in_data_section(sym) \ + (((sym)->n_type & (N_ABS | N_TEXT | N_DATA | N_BSS))== N_DATA) + +#define sym_in_bss_section(sym) \ + (((sym)->n_type & (N_ABS | N_TEXT | N_DATA | N_BSS))== N_BSS) + +/* Symbol is undefined if type is N_UNDF|N_EXT and if it has + zero in the "value" field. Nonzeroes there are fortrancommon + symbols. */ +#define sym_is_undefined(sym) \ + ((sym)->n_type == (N_UNDF | N_EXT) && (sym)->n_value == 0) + +/* Symbol is a global definition if N_EXT is on and if it has + a nonzero type field. */ +#define sym_is_global_defn(sym) \ + (((sym)->n_type & N_EXT) && (sym)->n_type & N_TYPE) + +/* Symbol is debugger info if any bits outside N_TYPE or N_EXT + are on. */ +#define sym_is_debugger_info(sym) \ + ((sym)->n_type & ~(N_EXT | N_TYPE)) + +#define sym_is_fortrancommon(sym) \ + (((sym)->n_type == (N_EXT)) && (sym)->n_value != 0) + +/* Symbol is absolute if it has N_ABS set */ +#define sym_is_absolute(sym) \ + (((sym)->n_type & N_TYPE)== N_ABS) + + +#define sym_is_indirect(sym) \ + (((sym)->n_type & N_ABS)== N_ABS) + +/* Only in their own functions for ease of debugging; when sym flags have + stabilised these should be inlined into their (single) caller */ + +static void +translate_from_native_sym_flags (sym_pointer, cache_ptr, abfd) + struct nlist *sym_pointer; + aout_symbol_type *cache_ptr; + bfd *abfd; +{ + switch (cache_ptr->type & N_TYPE) { + case N_SETA: + case N_SETT: + case N_SETD: + case N_SETB: + { + asection *section = bfd_make_section(abfd, + cache_ptr->symbol.name); + arelent_chain *reloc = (arelent_chain *)malloc(sizeof(arelent_chain)); + + switch ( (cache_ptr->type & N_TYPE) ) { + case N_SETA: + reloc->relent.section = (asection *)NULL; + cache_ptr->symbol.section = (asection *)NULL; + break; + case N_SETT: + reloc->relent.section = (asection *)obj_textsec(abfd); + cache_ptr->symbol.value -= reloc->relent.section->vma; + break; + case N_SETD: + reloc->relent.section = (asection *)obj_datasec(abfd); + cache_ptr->symbol.value -= reloc->relent.section->vma; + break; + case N_SETB: + reloc->relent.section = (asection *)obj_bsssec(abfd); + cache_ptr->symbol.value -= reloc->relent.section->vma; + break; + } + cache_ptr->symbol.section = reloc->relent.section; + reloc->relent.addend = cache_ptr->symbol.value ; + /* + We modify the symbol to belong to a section depending upon the + name of the symbol - probably __CTOR__ or __DTOR__ but we don't + really care, and add to the size of the section to contain a + pointer to the symbol. Build a reloc entry to relocate to this + symbol attached to this section. + */ + + + section->flags = SEC_CONSTRUCTOR; + section->reloc_count++; + section->alignment_power = 2; + reloc->relent.sym_ptr_ptr = (asymbol **)NULL; + reloc->next = section->constructor_chain; + section->constructor_chain = reloc; + reloc->relent.address = section->size; + section->size += sizeof(int *); + + reloc->relent.howto = howto_table +CTOR_TABLE_RELOC_IDX; + cache_ptr->symbol.flags |= BSF_DEBUGGING ; + } + break; + default: + + if (sym_is_debugger_info (sym_pointer)) { + cache_ptr->symbol.flags = BSF_DEBUGGING ; + /* Work out the section correct for this symbol */ + switch (sym_pointer->n_type & N_TYPE) + { + case N_TEXT: + case N_FN: + cache_ptr->symbol.section = obj_textsec (abfd); + cache_ptr->symbol.value -= obj_textsec(abfd)->vma; + break; + case N_DATA: + cache_ptr->symbol.value -= obj_datasec(abfd)->vma; + cache_ptr->symbol.section = obj_datasec (abfd); + break; + case N_BSS : + cache_ptr->symbol.section = obj_bsssec (abfd); + cache_ptr->symbol.value -= obj_bsssec(abfd)->vma; + break; + case N_ABS: + default: + cache_ptr->symbol.section = 0; + break; + } + } + else { + if (sym_is_fortrancommon (sym_pointer)) + { + cache_ptr->symbol.flags = BSF_FORT_COMM; + cache_ptr->symbol.section = (asection *)NULL; + } + else { + if (sym_is_undefined (sym_pointer)) { + cache_ptr->symbol.flags = BSF_UNDEFINED; + } + else if (sym_is_global_defn (sym_pointer)) { + cache_ptr->symbol.flags = BSF_GLOBAL | BSF_EXPORT; + } + + else if (sym_is_absolute (sym_pointer)) { + cache_ptr->symbol.flags = BSF_ABSOLUTE; + } + else { + cache_ptr->symbol.flags = BSF_LOCAL; + } + + /* In a.out, the value of a symbol is always relative to the + * start of the file, if this is a data symbol we'll subtract + * the size of the text section to get the section relative + * value. If this is a bss symbol (which would be strange) + * we'll subtract the size of the previous two sections + * to find the section relative address. + */ + + if (sym_in_text_section (sym_pointer)) { + cache_ptr->symbol.value -= obj_textsec(abfd)->vma; + cache_ptr->symbol.section = obj_textsec (abfd); + } + else if (sym_in_data_section (sym_pointer)){ + cache_ptr->symbol.value -= obj_datasec(abfd)->vma; + cache_ptr->symbol.section = obj_datasec (abfd); + } + else if (sym_in_bss_section(sym_pointer)) { + cache_ptr->symbol.section = obj_bsssec (abfd); + cache_ptr->symbol.value -= obj_bsssec(abfd)->vma; + } + else { + cache_ptr->symbol.section = (asection *)NULL; + cache_ptr->symbol.flags |= BSF_ABSOLUTE; + } + } + } + } +} +void +translate_to_native_sym_flags (sym_pointer, cache_ptr_g, abfd) + struct nlist *sym_pointer; + generic_symbol_type *cache_ptr_g; + bfd *abfd; +{ + asymbol *cache_ptr = (asymbol *)cache_ptr_g; + + /* FIXME check for wrigin bss */ + if (bfd_get_section(cache_ptr)) { + if (bfd_get_output_section(cache_ptr) == obj_bsssec (abfd)) { + sym_pointer->n_type |= N_BSS; + } + else if (bfd_get_output_section(cache_ptr) == obj_datasec (abfd)) { + sym_pointer->n_type |= N_DATA; + } + else if (bfd_get_output_section(cache_ptr) == obj_textsec (abfd)) { + sym_pointer->n_type |= N_TEXT; + } + else { + BFD_ASSERT(0); + } + /* Turn the symbol from section relative to absolute again */ + sym_pointer->n_value += + cache_ptr->section->output_section->vma + + cache_ptr->section->output_offset ; + } + else { + sym_pointer->n_type |= N_ABS; + } + + if (cache_ptr->flags & (BSF_FORT_COMM | BSF_UNDEFINED)) { + sym_pointer->n_type = (N_UNDF | N_EXT); + return; + } + + if (cache_ptr->flags & BSF_ABSOLUTE) { + sym_pointer->n_type |= N_ABS; + } + + if (cache_ptr->flags & (BSF_GLOBAL | BSF_EXPORT)) { + sym_pointer->n_type |= N_EXT; + } + if (cache_ptr->flags & BSF_DEBUGGING) { + sym_pointer->n_type = ((aout_symbol_type *)cache_ptr)->type; + } + +} + +/* Native-level interface to symbols. */ + +/* We read the symbols into a buffer, which is discarded when this + function exits. We read the strings into a buffer large enough to + hold them all plus all the cached symbol entries. */ + +asymbol * +sunos4_make_empty_symbol (abfd) +bfd *abfd; +{ + aout_symbol_type *new = + (aout_symbol_type *)zalloc (sizeof (aout_symbol_type)); + new->symbol.the_bfd = abfd; + + return &new->symbol; +} + +boolean +sunos4_slurp_symbol_table (abfd) + bfd *abfd; +{ + unsigned int symbol_count; + size_t symbol_size; + size_t string_size; + struct nlist *syms; + char *strings; + aout_symbol_type *cached; + + /* If there's no work to be done, don't do any */ + if (obj_aout_symbols (abfd) != (aout_symbol_type *)NULL) return true; + symbol_size = exec_hdr(abfd)->a_syms; + if (symbol_size == 0) { + bfd_error = no_symbols; + return false; + } + + bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET); + if (bfd_read ((void *)&string_size, 4, 1, abfd) != 4) + return false; + string_size = bfd_h_getlong (abfd, (unsigned char *)&string_size); + + symbol_count = symbol_size / sizeof (struct nlist); + + /* Malloc (should alloca) space for native symbols, and + malloc space for string table and symbol cache. */ + + syms = (struct nlist *) zalloc (symbol_size); + if (syms == NULL) { + bfd_error = no_memory; + return false; + } + + cached = (aout_symbol_type *) zalloc ((size_t)(string_size + 1 + + (symbol_count * sizeof (aout_symbol_type)))); + if (cached == NULL) { + bfd_error = no_memory; + free ((void *)syms); + return false; + } + + strings = ((char *) cached) + (symbol_count * sizeof (aout_symbol_type)); + + bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET); + if (bfd_read ((void *)syms, 1, symbol_size, abfd) != symbol_size) { + bailout: + free ((void *)cached); + free ((void*)syms); + return false; + } + + bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET); + if (bfd_read ((void *)strings, 1, string_size, abfd) != string_size) { + goto bailout; + } + + /* OK, now walk the new symtable, cacheing symbol properties */ + { + register struct nlist *sym_pointer; + register struct nlist *sym_end = syms + symbol_count; + register aout_symbol_type *cache_ptr = cached; + + if (bfd_header_twiddle_required (abfd) == true) { + /* run through the table and byte swap if needed */ + for (sym_pointer = syms; sym_pointer < sym_end; sym_pointer++) { + sym_pointer->n_un.n_strx = + bfd_h_get_x (abfd, &sym_pointer->n_un.n_strx); + sym_pointer->n_desc = + bfd_h_get_x (abfd, &sym_pointer->n_desc); + sym_pointer->n_value = + bfd_h_get_x (abfd, &sym_pointer->n_value); + sym_pointer->n_other = (char) + bfd_h_get_x(abfd, &sym_pointer->n_other); + sym_pointer->n_type = (char) + bfd_h_get_x(abfd, &sym_pointer->n_type); + + } + } + /* Run through table and copy values */ + for (sym_pointer = syms, cache_ptr = cached; + sym_pointer < sym_end; sym_pointer++, cache_ptr++) + { + cache_ptr->symbol.the_bfd = abfd; + if (sym_pointer->n_un.n_strx) + cache_ptr->symbol.name = sym_pointer->n_un.n_strx + strings; + else + cache_ptr->symbol.name = (char *)NULL; + cache_ptr->symbol.value = sym_pointer->n_value; + cache_ptr->desc = sym_pointer->n_desc; + cache_ptr->other = sym_pointer->n_other; + cache_ptr->type = sym_pointer->n_type; + cache_ptr->symbol.udata = 0; + translate_from_native_sym_flags (sym_pointer, cache_ptr, abfd); + + } + } + + obj_aout_symbols (abfd) = cached; + bfd_get_symcount (abfd) = symbol_count; + free ((void *)syms); + + return true; +} + + +void +sunos4_write_syms (abfd) + bfd *abfd; +{ + unsigned int count ; + asymbol **generic = bfd_get_outsymbols (abfd); + + unsigned int stindex = sizeof(stindex); /* initial string length */ + + for (count = 0; count < bfd_get_symcount (abfd); count++) { + asymbol *g = generic[count]; + struct nlist nsp; + + if (g->name) { + unsigned int length = strlen(g->name) +1; + bfd_h_putlong (abfd, stindex, (unsigned char *)&nsp.n_un.n_strx); + stindex += length; + } + else { + bfd_h_putlong (abfd, 0, (unsigned char *)&nsp.n_un.n_strx); + } + + if (g->the_bfd->xvec->flavour == abfd->xvec->flavour) + { + nsp.n_desc = aout_symbol( g)->desc; + nsp.n_other = aout_symbol(g)->other; + nsp.n_type = aout_symbol(g)->type; + } + else + { + nsp.n_desc = 0; + nsp.n_other = 0; + nsp.n_type = 0; + } + + + nsp.n_value = g->value; + translate_to_native_sym_flags (&nsp, (generic_symbol_type *)g, abfd); + + + bfd_h_putshort (abfd, nsp.n_desc, (unsigned char *)&nsp.n_desc); + bfd_h_putlong (abfd, nsp.n_value, (unsigned char *)&nsp.n_value); + bfd_write((void *)&nsp,1, sizeof(nsp), abfd); + } + + + /* Now output the strings. Be sure to put string length into correct + * byte ordering before writing it. + */ + bfd_h_putlong (abfd, stindex, (unsigned char *)&stindex); + + bfd_write((void *)&stindex, 1, sizeof(stindex), abfd); + + generic = bfd_get_outsymbols(abfd); + for (count = 0; count < bfd_get_symcount(abfd); count++) + { + asymbol *g = *(generic++); + + if (g->name != (char *)NULL) + { + size_t length = strlen(g->name)+1; + bfd_write((void *)g->name, 1, length, abfd); + } + if ((g->flags & BSF_FAKE)==0) { + g->name = itos(count); /* smash the generic symbol */ + } + } +} + + +void +sunos4_reclaim_symbol_table (abfd) + bfd *abfd; +{ + asection *section; + + if (!bfd_get_symcount (abfd)) return; + + for (section = abfd->sections; + section != (asection *) NULL; + section = section->next) + if (section->relocation) { + free ((void *)section->relocation); + section->relocation = NULL; + section->reloc_count = 0; + } + + bfd_get_symcount (abfd) = 0; + free ((void *)obj_aout_symbols (abfd)); + obj_aout_symbols (abfd) = (aout_symbol_type *)NULL; +} + +unsigned int +sunos4_get_symtab_upper_bound (abfd) + bfd *abfd; +{ + if (!sunos4_slurp_symbol_table (abfd)) return 0; + + return (bfd_get_symcount (abfd)+1) * (sizeof (aout_symbol_type *)); +} + +unsigned int +sunos4_get_symtab (abfd, location) + bfd *abfd; + asymbol **location; +{ + unsigned int counter = 0; + aout_symbol_type *symbase; + + if (!sunos4_slurp_symbol_table (abfd)) return 0; + + for (symbase = obj_aout_symbols(abfd); counter++ < bfd_get_symcount (abfd);) + *(location++) = (asymbol *)( symbase++); + *location++ =0; + return bfd_get_symcount(abfd); +} + + +/* Obsolete procedural interface; better to look at the cache directly */ + +/* User should have checked the file flags; perhaps we should return + BFD_NO_MORE_SYMBOLS if there are none? */ + +int +sunos4_get_symcount_upper_bound (abfd) + bfd *abfd; +{ + /* In case we're doing an output file or something...? */ + if (bfd_get_symcount (abfd)) return bfd_get_symcount (abfd); + + return (exec_hdr (abfd)->a_syms) / (sizeof (struct nlist)); +} + +symindex +sunos4_get_first_symbol (ignore_abfd) + bfd * ignore_abfd; +{ + return 0; +} + +symindex +sunos4_get_next_symbol (abfd, oidx) + bfd *abfd; + symindex oidx; +{ + if (oidx == BFD_NO_MORE_SYMBOLS) return BFD_NO_MORE_SYMBOLS; + return ++oidx >= bfd_get_symcount (abfd) ? BFD_NO_MORE_SYMBOLS : oidx; +} + +char * +sunos4_symbol_name (abfd, idx) + bfd *abfd; + symindex idx; +{ + return (obj_aout_symbols (abfd) + idx)->symbol.name; +} + +long +sunos4_symbol_value (abfd, idx) + bfd *abfd; + symindex idx; +{ + return (obj_aout_symbols (abfd) + idx)->symbol.value; +} + +symclass +sunos4_classify_symbol (abfd, idx) + bfd *abfd; + symindex idx; +{ + aout_symbol_type *sym = obj_aout_symbols (abfd) + idx; + + if ((sym->symbol.flags & BSF_FORT_COMM) != 0) return bfd_symclass_fcommon; + if ((sym->symbol.flags & BSF_GLOBAL) != 0) return bfd_symclass_global; + if ((sym->symbol.flags & BSF_DEBUGGING) != 0) return bfd_symclass_debugger; + if ((sym->symbol.flags & BSF_UNDEFINED) != 0) return bfd_symclass_undefined; + + return bfd_symclass_unknown; +} + +boolean +sunos4_symbol_hasclass (abfd, idx, class) + bfd *abfd; + symindex idx; + symclass class; +{ + aout_symbol_type *sym = obj_aout_symbols (abfd) + idx; + switch (class) { + case bfd_symclass_fcommon: + return (sym->symbol.flags & BSF_FORT_COMM) ? true :false; + case bfd_symclass_global: + return (sym->symbol.flags & BSF_GLOBAL) ? true:false; + case bfd_symclass_debugger: + return (sym->symbol.flags & BSF_DEBUGGING) ? true:false;; + case bfd_symclass_undefined: + return (sym->symbol.flags & BSF_UNDEFINED) ? true:false;; + default: return false; + } +} + +/** Some reloc hackery */ + + +boolean +sunos4_slurp_reloc_table (abfd, asect, symbols) + bfd *abfd; + sec_ptr asect; + asymbol **symbols; +{ + unsigned int count; + size_t reloc_size; + struct reloc_info_extended *relocs; + arelent *reloc_cache; + + 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_error = invalid_operation; + return false; + + doit: + bfd_seek (abfd, asect->rel_filepos, SEEK_SET); + count = reloc_size / sizeof (struct reloc_info_extended); + + relocs = (struct reloc_info_extended *) malloc (reloc_size); + if (!relocs) { + bfd_error = no_memory; + return false; + } + reloc_cache = (arelent *) zalloc ((size_t)(count * sizeof (arelent))); + if (reloc_cache == (arelent *)NULL) { + free ((void *)relocs); + bfd_error = no_memory; + return false; + } + + if (bfd_read ((void*) relocs, 1, reloc_size, abfd) != reloc_size) { + bfd_error = system_call_error; + free (reloc_cache); + free (relocs); + return false; + } + + { + register struct reloc_info_extended *rptr = relocs; + unsigned int counter = 0; + arelent *cache_ptr = reloc_cache; + + for (; counter < count; counter++, rptr++, cache_ptr++) { + /* john's old swap_reloc was a hell of a lot hairier... */ + /* FIXME, it needs to be!!! */ + rptr->r_address = bfd_h_getlong (abfd, &rptr->r_address); + /* FIXME NOW! + * The following can't be done because r_index is a bit field: + * + * rptr->r_index = bfd_h_getlong (abfd, &rptr->r_index); + */ + rptr->r_addend = bfd_h_getlong (abfd, &rptr->r_addend); + if (rptr->r_extern) { + /* If this bit is set then the r_index is a index into the symbol table + * if the bit is not set then r_index contains a section map. + * We either fill in the sym entry with a pointer to the symbol, + * or point to the correct section + */ + + cache_ptr->sym_ptr_ptr = symbols + rptr->r_index; + cache_ptr->addend = rptr->r_addend; + cache_ptr->section = (asection *)NULL; + } + else + { + /* Remember that in a.out symbols are relative to the + beginning of the file rather than sections ? (look in + translate_from_native_sym_flags) The reloc entry addend + has added to it the offset into the file of the data, so + subtract the base to make the reloc section relative */ + + cache_ptr->sym_ptr_ptr = (asymbol **)NULL; + switch (rptr->r_index) { + case N_TEXT: + case N_TEXT | N_EXT: + cache_ptr->section = obj_textsec(abfd); + cache_ptr->addend = rptr->r_addend - obj_textsec(abfd)->vma ; + break; + case N_DATA: + case N_DATA | N_EXT: + cache_ptr->section = obj_datasec(abfd); + cache_ptr->addend = rptr->r_addend - obj_datasec(abfd)->vma ; + break; + case N_BSS: + case N_BSS | N_EXT: + cache_ptr->section = obj_bsssec(abfd); + cache_ptr->addend = rptr->r_addend - obj_bsssec(abfd)->vma; + break; + case N_ABS: + case N_ABS | N_EXT: + BFD_ASSERT(1); + break; + default: + BFD_ASSERT(1); + break; + } + + } + + cache_ptr->address = rptr->r_address; + cache_ptr->howto = howto_table + (unsigned int)( rptr->r_type); + } + } + + free (relocs); + asect->relocation = reloc_cache; + asect->reloc_count = count; + return true; +} + +static boolean +sunos4_squirt_out_relocs (abfd, section) + bfd *abfd; + asection *section; +{ + arelent **generic; + + unsigned int count = section->reloc_count; + struct reloc_info_extended *native, *natptr; + size_t natsize = count * sizeof (struct reloc_info_extended); + + if (count == 0) return true; + generic = section->orelocation; + native = ((struct reloc_info_extended *) zalloc (natsize)); + if (!native) { + bfd_error = no_memory; + return false; + } + + for (natptr = native; count != 0; --count, ++natptr, ++generic) + { + arelent *g = *generic; + + natptr->r_address = g->address; + /* Find a type in the output format which matches the input howto - + * at the moment we assume input format == output format FIXME!! + */ + natptr->r_type = (enum reloc_type) g->howto->type; + /* name clobbered by sunos4_write_syms to be symbol index*/ + + if (g->sym_ptr_ptr != (asymbol **)NULL) + { + if ((*(g->sym_ptr_ptr))->section) { + /* replace the section offset into the addent */ + g->addend += (*(g->sym_ptr_ptr))->section->vma; + } + + natptr->r_index = stoi((*(g->sym_ptr_ptr))->name); + BFD_ASSERT(natptr->r_index < 0xfff); + natptr->r_extern = 1; + natptr->r_addend = g->addend; + } + else { + natptr->r_extern = 0; + if (g->section == (asection *)NULL) { + BFD_ASSERT(0); + natptr->r_index = N_ABS | N_EXT; + natptr->r_addend = g->addend; + } + else if(g->section->output_section == obj_textsec(abfd)) { + natptr->r_index = N_TEXT | N_EXT; + natptr->r_addend = g->addend + obj_textsec(abfd)->vma; + } + else if (g->section->output_section == obj_datasec(abfd)) { + natptr->r_index = N_DATA | N_EXT; + natptr->r_addend = g->addend + obj_datasec(abfd)->vma; + } + else if (g->section->output_section == obj_bsssec(abfd)) { + natptr->r_index = N_BSS | N_EXT ; + natptr->r_addend = g->addend + obj_bsssec(abfd)->vma; + + } + else { + BFD_ASSERT(0); + } + } + + if ( bfd_header_twiddle_required(abfd) ){ + bfd_h_putlong ( abfd, natptr->r_address, &natptr->r_address ); + + /* FIXME -- NOW! + * + * I came through here as part of my campaign to make compile-time + * definition of host and target byte orders unnecessary. The new + * code won't even compile because but r_index is a bit field. + * But the simple-minded byte swap that was here before wasn't going + * to work on a bit field anyway. + * + * The old code used to be #ifdef'd on + * TARGET_BYTE_ORDER_BIG_P != HOST_BYTE_ORDER_BIG_P + * Apparently, it was never tested in such a condition: the + * macro invocations here (of swapoutlong) had the wrong number + * of arguments and would never have compiled. + * Chris + bfd_h_putlong ( abfd, natptr->r_index, &natptr->r_index ); + */ + + bfd_h_putlong ( abfd, natptr->r_addend, &natptr->r_addend ); + } + + } + + if ( bfd_write ((void *) native, 1, natsize, abfd) != natsize) { + free(native); + return false; + } + free (native); + + return true; +} + +/* This is stupid. This function should be a boolean predicate */ +unsigned int +sunos4_canonicalize_reloc (abfd, section, relptr, symbols) + bfd *abfd; + sec_ptr section; + arelent **relptr; + asymbol **symbols; +{ + arelent *tblptr = section->relocation; + unsigned int count; + + if (!(tblptr || sunos4_slurp_reloc_table (abfd, section, symbols))) + return 0; + + 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; + if (!tblptr) return 0; + + for (count = 0; count++ < section->reloc_count;) + { + *relptr++ = tblptr++; + } + } + *relptr = 0; + + return section->reloc_count; +} + +unsigned int +sunos4_get_reloc_upper_bound (abfd, asect) + bfd *abfd; + sec_ptr asect; +{ + if (bfd_get_format (abfd) != bfd_object) { + bfd_error = invalid_operation; + return 0; + } + if (asect->flags & SEC_CONSTRUCTOR) { + return (sizeof (arelent *) * (asect->reloc_count+1)); + } + + if (asect == obj_datasec (abfd)) + return (sizeof (arelent *) * + ((exec_hdr(abfd)->a_drsize / sizeof (struct reloc_info_extended)) + +1)); + + if (asect == obj_textsec (abfd)) + return (sizeof (arelent *) * + ((exec_hdr(abfd)->a_trsize / sizeof (struct reloc_info_extended)) + +1)); + + bfd_error = invalid_operation; + return 0; +} + +void +sunos4_reclaim_reloc (ignore_abfd, section) + bfd *ignore_abfd; + sec_ptr section; +{ + if (section->relocation) { + free (section->relocation); + section->relocation = NULL; + section->reloc_count = 0; + } +} + + +alent * +sunos4_get_lineno(ignore_abfd, ignore_symbol) +bfd *ignore_abfd; +generic_symbol_type *ignore_symbol; +{ +return (alent *)NULL; +} + +void +sunos4_print_symbol(ignore_abfd, file, symbol, how) +bfd *ignore_abfd; +FILE *file; +asymbol *symbol; +bfd_print_symbol_enum_type how; +{ + switch (how) { + case bfd_print_symbol_name_enum: + fprintf(file,"%s", symbol->name); + break; + case bfd_print_symbol_type_enum: + fprintf(file,"%4x %2x %2x",(unsigned)(aout_symbol(symbol)->desc & 0xffff), + (unsigned)( aout_symbol(symbol)->other & 0xff), + (unsigned)(aout_symbol(symbol)->type)); + break; + case bfd_print_symbol_all_enum: + { + char *section_name = symbol->section == (asection *)NULL ? + "*abs" : symbol->section->name; + + bfd_print_symbol_vandf((void *)file,symbol); + + fprintf(file," %-5s %04x %02x %02x %s", + section_name, + (unsigned)(aout_symbol(symbol)->desc & 0xffff), + (unsigned)(aout_symbol(symbol)->other & 0xff), + (unsigned)(aout_symbol(symbol)->type & 0xff), + symbol->name); + } + break; + } +} +/* Once we know all the stuff that could be consed, we know how to clean + it up. So why don't we? */ + +boolean +sunos4_close_and_cleanup (abfd) + bfd *abfd; +{ + if (!bfd_read_p (abfd)) + switch (abfd->format) { + case bfd_archive: + if (!_bfd_write_archive_contents (abfd)) return false; break; + case bfd_object: + if (!sunos4_write_object_contents (abfd)) return false; break; + default: bfd_error = invalid_operation; return false; + } + +#define cleaner(ptr) if (abfd->ptr) free (abfd->ptr) + cleaner (tdata); + + if (abfd->my_archive) + cleaner (filename); + +#undef cleaner + return true; +} + +/* + provided a bfd, a section and an offset into the section, calculate + and return the name of the source file and the line nearest to the + wanted location. +*/ + +boolean +sunos4_find_nearest_line(abfd, + section, + symbols, + offset, + filename_ptr, + functionname_ptr, + line_ptr) +bfd *abfd; +asection *section; +asymbol **symbols; +bfd_vma offset; +char **filename_ptr; +char **functionname_ptr; +unsigned int *line_ptr; +{ + /* Run down the file looking for the filename, function and linenumber */ + asymbol **p; + static char buffer[100]; + bfd_vma high_line_vma = ~0; + bfd_vma low_func_vma = 0; + asymbol *func = 0; + *filename_ptr = abfd->filename; + *functionname_ptr = 0; + *line_ptr = 0; + if (symbols != (asymbol **)NULL) { + for (p = symbols; *p; p++) { + aout_symbol_type *q = (aout_symbol_type *)(*p); + switch (q->type){ + case N_SO: + *filename_ptr = q->symbol.name; + if (obj_textsec(abfd) != section) { + return true; + } + break; + case N_SLINE: + + case N_DSLINE: + case N_BSLINE: + /* We'll keep this if it resolves nearer than the one we have already */ + if (q->symbol.value >= offset && + q->symbol.value < high_line_vma) { + *line_ptr = q->desc; + high_line_vma = q->symbol.value; + } + break; + case N_FUN: + { + /* We'll keep this if it is nearer than the one we have already */ + if (q->symbol.value >= low_func_vma && + q->symbol.value <= offset) { + low_func_vma = q->symbol.value; + func = (asymbol *)q; + } + if (*line_ptr && func) { + char *function = func->name; + char *p; + strncpy(buffer, function, sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = 0; + /* Have to remove : stuff */ + p = strchr(buffer,':'); + if (p != NULL) {*p = NULL; } + *functionname_ptr = buffer; + return true; + + } + } + break; + } + } + } + + return true; + +} + +bfd_target aoutvec = +{ + "a.out-generic-big", /* name */ + bfd_target_aout_flavour_enum, + true, /* target byte order */ + true, /* target headers byte order */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED), + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* valid reloc types */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + sunos4_close_and_cleanup, /* _close_and_cleanup */ + sunos4_set_section_contents, /* bfd_set_section_contents */ + sunos4_get_section_contents, /* bfd_get_section_contents */ + sunos4_new_section_hook, /* new_section_hook */ + sunos4_core_file_failing_command, /* _core_file_failing_command */ + sunos4_core_file_failing_signal, /* _core_file_failing_signal */ + sunos4_core_file_matches_executable_p, /* _core_file_matches_ex...p */ + + bfd_slurp_bsd_armap, /* bfd_slurp_armap */ + bfd_true, /* bfd_slurp_extended_name_table */ + bfd_bsd_truncate_arname, /* bfd_truncate_arname */ + + sunos4_get_symtab_upper_bound, /* get_symtab_upper_bound */ + sunos4_get_symtab, /* canonicalize_symtab */ + sunos4_reclaim_symbol_table, /* bfd_reclaim_symbol_table */ + sunos4_get_reloc_upper_bound, /* get_reloc_upper_bound */ + sunos4_canonicalize_reloc, /* bfd_canonicalize_reloc */ + sunos4_reclaim_reloc, /* bfd_reclaim_reloc */ + sunos4_get_symcount_upper_bound, /* bfd_get_symcount_upper_bound */ + sunos4_get_first_symbol, /* bfd_get_first_symbol */ + sunos4_get_next_symbol, /* bfd_get_next_symbol */ + sunos4_classify_symbol, /* bfd_classify_symbol */ + sunos4_symbol_hasclass, /* bfd_symbol_hasclass */ + sunos4_symbol_name, /* bfd_symbol_name */ + sunos4_symbol_value, /* bfd_symbol_value */ + + _do_getblong, _do_putblong, _do_getbshort, _do_putbshort, /* data */ + _do_getblong, _do_putblong, _do_getbshort, _do_putbshort, /* hdrs */ + + {_bfd_dummy_target, sunos4_object_p, /* bfd_check_format */ + bfd_generic_archive_p, sunos4_core_file_p}, + {bfd_false, sunos4_mkobject, /* bfd_zxset_format */ + _bfd_generic_mkarchive, bfd_false}, + sunos4_make_empty_symbol, + sunos4_print_symbol, + sunos4_get_lineno, + sunos4_set_arch_mach, + bsd_write_armap, + bfd_generic_openr_next_archived_file, + sunos4_find_nearest_line, /* bfd_find_nearest_line */ + bfd_generic_stat_arch_elt /* bfd_stat_arch_elt */ + }; + diff --git a/bfd/archive.c b/bfd/archive.c new file mode 100644 index 00000000000..53cd0bd7c7f --- /dev/null +++ b/bfd/archive.c @@ -0,0 +1,1223 @@ +/*** archive.c -- an attempt at combining the machine-independent parts of + archives */ + +/* Copyright (C) 1990, 1991 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Diddler. + +BFD 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 1, or (at your option) +any later version. + +BFD 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 BFD; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* Assumes: + o - all archive elements start on an even boundary, newline padded; + o - all arch headers are char *; + o - all arch headers are the same size (across architectures). +*/ + +/* $Id$ + * $Log$ + * Revision 1.1 1991/03/21 21:10:42 gumby + * Initial revision + * + * Revision 1.3 1991/03/16 05:55:25 rich + * pop + * + * Revision 1.2 1991/03/15 18:15:50 rich + * *** empty log message *** + * + * Revision 1.7 1991/03/08 04:18:02 rich + * *** empty log message *** + * + * Revision 1.6 1991/03/07 21:55:31 sac + * Added primitive file caching, a file open only for input and + * less than BFD_INCORE_FILE_SIZE will be malloced and read in + * only once. + * + * Revision 1.5 1991/03/05 16:31:12 sac + * lint + * + */ + + +#include "sysdep.h" +#include "bfd.h" +#include "libbfd.h" +#include "ar.h" +#include "ranlib.h" + +/* We keep a cache of archive filepointers to archive elements to + speed up searching the archive by filepos. We only add an entry to + the cache when we actually read one. We also don't sort the cache; + it's short enough to search linearly. + Note that the pointers here point to the front of the ar_hdr, not + to the front of the contents! +*/ +struct ar_cache { + file_ptr ptr; + bfd* arelt; + struct ar_cache *next; +}; + +#define ar_padchar(abfd) ((abfd)->xvec->ar_pad_char) +#define ar_maxnamelen(abfd) ((abfd)->xvec->ar_max_namelen) + +#define arch_hdr(bfd) ((struct ar_hdr *) \ + (((struct areltdata *)((bfd)->arelt_data))->arch_header)) + + + +boolean +_bfd_generic_mkarchive (abfd) + bfd *abfd; +{ + abfd->tdata =(void *) zalloc (sizeof (struct artdata)); + + if (abfd->tdata == NULL) { + bfd_error = no_memory; + return false; + } +bfd_ardata(abfd)->cache = 0; + return true; +} + +symindex +bfd_get_next_mapent (abfd, prev, entry) + bfd *abfd; + symindex prev; + carsym **entry; +{ + if (!bfd_has_map (abfd)) { + bfd_error = invalid_operation; + return BFD_NO_MORE_SYMBOLS; + } + + if (prev == BFD_NO_MORE_SYMBOLS) prev = 0; + else if (++prev >= (symindex)(bfd_ardata (abfd)->symdef_count)) + return BFD_NO_MORE_SYMBOLS; + + *entry = (bfd_ardata (abfd)->symdefs + prev); + return prev; +} + + +/* To be called by backends only */ +bfd * +_bfd_create_empty_archive_element_shell (obfd) + bfd *obfd; +{ + bfd *nbfd; + + nbfd = new_bfd_contained_in(obfd); + if (nbfd == NULL) { + bfd_error = no_memory; + return NULL; + } + return nbfd; +} + +boolean +bfd_set_archive_head (output_archive, new_head) + bfd *output_archive, *new_head; +{ + + output_archive->archive_head = new_head; + return true; +} + +bfd * +look_for_bfd_in_cache (arch_bfd, filepos) + bfd *arch_bfd; + file_ptr filepos; +{ + struct ar_cache *current; + + for (current = bfd_ardata (arch_bfd)->cache; current != NULL; + current = current->next) + if (current->ptr == filepos) return current->arelt; + + return NULL; +} + +/* Kind of stupid to call cons for each one, but we don't do too many */ +boolean +add_bfd_to_cache (arch_bfd, filepos, new_elt) + bfd *arch_bfd, *new_elt; + file_ptr filepos; +{ + struct ar_cache *new_cache = ((struct ar_cache *) + zalloc (sizeof (struct ar_cache))); + + if (new_cache == NULL) { + bfd_error = no_memory; + return false; + } + + new_cache->ptr = filepos; + new_cache->arelt = new_elt; + new_cache->next = (struct ar_cache *)NULL; + if (bfd_ardata (arch_bfd)->cache == NULL) + bfd_ardata (arch_bfd)->cache = new_cache; + else { + struct ar_cache *current = bfd_ardata (arch_bfd)->cache; + + for (; current->next != NULL; current = current->next); + current->next = new_cache; + } + + return true; +} + + + +/* The name begins with space. Hence the rest of the name is an index into + the string table. */ + +char * +get_extended_arelt_filename (arch, name) + bfd *arch; + char *name; +{ + extern int errno; + unsigned long index = 0; + + /* Should extract string so that I can guarantee not to overflow into + the next region, but I"m too lazy. */ + errno = 0; + index = strtol (name, NULL, 10); + if (errno != 0) { + bfd_error = malformed_archive; + return NULL; + } + + return bfd_ardata (arch)->extended_names + index; +} + +/* This functions reads an arch header and returns an areltdata pointer, or + NULL on error. + + Presumes the file pointer is already in the right place (ie pointing + to the ar_hdr in the file). Moves the file pointer; on success it + should be pointing to the front of the file contents; on failure it + could have been moved arbitrarily. +*/ + +struct areltdata * +snarf_ar_hdr (abfd) + bfd *abfd; +{ + extern int errno; + struct ar_hdr hdr; + char *hdrp = (char *) &hdr; + unsigned int parsed_size; + struct areltdata *ared; + char *filename = NULL; + unsigned int namelen = 0; + unsigned int allocsize = sizeof (struct areltdata) + sizeof (struct ar_hdr); + char *allocptr; + + if (bfd_read ((void *)hdrp, 1, sizeof (struct ar_hdr), abfd) + != sizeof (struct ar_hdr)) { + bfd_error = no_more_archived_files; + return NULL; + } + if (strncmp ((hdr.ar_fmag), ARFMAG, 2)) { + bfd_error = malformed_archive; + return NULL; + } + + errno = 0; + parsed_size = strtol (hdr.ar_size, NULL, 10); + if (errno != 0) { + bfd_error = malformed_archive; + return NULL; + } + + /* extract the filename from the archive */ + if (hdr.ar_name[0] == ' ' && bfd_ardata (abfd)->extended_names != NULL) { + filename = get_extended_arelt_filename (abfd, hdr.ar_name); + if (filename == NULL) { + bfd_error = malformed_archive; + return NULL; + } + } + else + { + /* We judge the end of the name by looking for a space or a + padchar */ + + namelen = 0; + + while (namelen < ar_maxnamelen(abfd) && + ( hdr.ar_name[namelen] != 0 && + hdr.ar_name[namelen] != ' ' && + hdr.ar_name[namelen] != ar_padchar(abfd))) { + namelen++; + } + + allocsize += namelen + 1; + } + + allocptr = zalloc (allocsize); + if (allocptr == NULL) { + bfd_error = no_memory; + return NULL; + } + + ared = (struct areltdata *) allocptr; + + ared->arch_header = allocptr + sizeof (struct areltdata); + memcpy ((char *) ared->arch_header, &hdr, sizeof (struct ar_hdr)); + ared->parsed_size = parsed_size; + + if (filename != NULL) ared->filename = filename; + else { + ared->filename = allocptr + (sizeof (struct areltdata) + + sizeof (struct ar_hdr)); + if (namelen) + memcpy (ared->filename, hdr.ar_name, namelen); + ared->filename[namelen] = '\0'; + } + + return ared; +} + +bfd * +get_elt_at_filepos (archive, filepos) + bfd *archive; + file_ptr filepos; +{ + struct areltdata *new_areldata; + bfd *n_nfd; + + n_nfd = look_for_bfd_in_cache (archive, filepos); + if (n_nfd) return n_nfd; + + if (0 > bfd_seek (archive, filepos, SEEK_SET)) { + bfd_error = system_call_error; + return NULL; + } + + if ((new_areldata = snarf_ar_hdr (archive)) == NULL) return NULL; + + n_nfd = _bfd_create_empty_archive_element_shell (archive); + if (n_nfd == NULL) { + free (new_areldata); + return NULL; + } + n_nfd->origin = bfd_tell (archive); + n_nfd->arelt_data = (void *) new_areldata; + n_nfd->filename = new_areldata->filename; + + if (add_bfd_to_cache (archive, filepos, n_nfd)) + return n_nfd; + + /* huh? */ + free (new_areldata); + free (n_nfd); + return NULL; +} + +bfd * +bfd_get_elt_at_index (abfd, index) + bfd *abfd; + int index; +{ + bfd *result = + get_elt_at_filepos + (abfd, (bfd_ardata (abfd)->symdefs + index)->file_offset); + return result; +} + +/* If you've got an archive, call this to read each subfile. */ +bfd * +bfd_openr_next_archived_file (archive, last_file) + bfd *archive, *last_file; +{ + + if ((bfd_get_format (archive) != bfd_archive) || + (archive->direction == write_direction)) { + bfd_error = invalid_operation; + return NULL; + } + + + return BFD_SEND (archive, + openr_next_archived_file, + (archive, + last_file)); + +} + +bfd *bfd_generic_openr_next_archived_file(archive, last_file) + bfd *archive; + bfd *last_file; +{ + file_ptr filestart; + + if (!last_file) + filestart = bfd_ardata (archive)->first_file_filepos; + else { + unsigned int size = arelt_size(last_file); + filestart = last_file->origin +size + size %2; +} + + + + return get_elt_at_filepos (archive, filestart); +} + + +bfd_target * +bfd_generic_archive_p (abfd) + bfd *abfd; +{ + char armag[SARMAG+1]; + + if (bfd_read ((void *)armag, 1, SARMAG, abfd) != SARMAG) { + bfd_error = wrong_format; + return 0; + } + + if (strncmp (armag, ARMAG, SARMAG)) return 0; + + bfd_set_ardata(abfd, (struct artdata *) zalloc (sizeof (struct artdata))); + + if (bfd_ardata (abfd) == NULL) { + bfd_error = no_memory; + return 0; + } + + bfd_ardata (abfd)->first_file_filepos = SARMAG; + + if (!BFD_SEND (abfd, _bfd_slurp_armap, (abfd))) { + free (bfd_ardata (abfd)); + abfd->tdata = NULL; + return 0; + } + + /* armap could be left ungc'd! FIXME -- potential storage leak */ + if (!BFD_SEND (abfd, _bfd_slurp_extended_name_table, (abfd))) { + free (bfd_ardata (abfd)); + abfd->tdata = NULL; + return 0; + } + + return abfd->xvec; +} + +/* Returns false on error, true otherwise */ +boolean +bfd_slurp_bsd_armap (abfd) + bfd *abfd; +{ + struct areltdata *mapdata; + char nextname[17]; + unsigned int counter = 0; + int *raw_armap, *rbase; + struct artdata *ardata = bfd_ardata (abfd); + char *stringbase; + + if (bfd_read ((void *)nextname, 1, 16, abfd) == 16) { + /* The archive has at least 16 bytes in it */ + bfd_seek (abfd, -16L, SEEK_CUR); + + if (strncmp (nextname, "__.SYMDEF ", 16)) { + bfd_has_map (abfd) = false; + return true; + } + + mapdata = snarf_ar_hdr (abfd); + if (mapdata == NULL) return false; + + raw_armap = (int *) zalloc (mapdata->parsed_size); + if (raw_armap == NULL) { + bfd_error = no_memory; + byebye: + free (mapdata); + return false; + } + + if (bfd_read ((void *)raw_armap, 1, mapdata->parsed_size, abfd) != + mapdata->parsed_size) { + bfd_error = malformed_archive; + free (raw_armap); + goto byebye; + } + + ardata->symdef_count = *(raw_armap) / sizeof (struct symdef); + ardata->cache = 0; + rbase = raw_armap+1; + ardata->symdefs = (carsym *) rbase; + stringbase = ((char *) (ardata->symdefs + ardata->symdef_count)) + 4; + + for (;counter < (unsigned)( ardata->symdef_count); counter++) { + struct symdef *sym = ((struct symdef *) rbase) + counter; + sym->s.name = sym->s.string_offset + stringbase; + } + + ardata->first_file_filepos = bfd_tell (abfd); + /* Pad to an even boundary if you have to */ + ardata->first_file_filepos += (ardata-> first_file_filepos) %2; + free (mapdata); + bfd_has_map (abfd) = true; + } + return true; +} + +/* Returns false on error, true otherwise */ +boolean +bfd_slurp_coff_armap (abfd) + bfd *abfd; +{ + struct areltdata *mapdata; + char nextname; + int *raw_armap, *rawptr; + struct artdata *ardata = bfd_ardata (abfd); + char *stringbase; + unsigned int stringsize; + carsym *carsyms; + + if (bfd_read ((void *)&nextname, 1, 1, abfd) != 1) { + bfd_has_map(abfd) = false; + return true; + } + + if (nextname != '/') { + /* Actually I think this is an error for a COFF archive */ + bfd_has_map (abfd) = false; + return true; + } + + bfd_seek (abfd, -1L, SEEK_CUR); + mapdata = snarf_ar_hdr (abfd); + if (mapdata == NULL) return false; + + raw_armap = (int *) zalloc (mapdata->parsed_size); + if (raw_armap == NULL) { + bfd_error = no_memory; + byebye: + free (mapdata); + return false; + } + + if (bfd_read ((void *)raw_armap, 1, mapdata->parsed_size, abfd) != + mapdata->parsed_size) { + bfd_error = malformed_archive; + oops: + free (raw_armap); + goto byebye; + } + + /* The coff armap must be read sequentially. So we construct a bsd-style + one in core all at once, for simplicity. */ + + stringsize = mapdata->parsed_size - (4 * (*raw_armap)) - 4; + + { + unsigned int nsymz = *raw_armap; + unsigned int carsym_size = (nsymz * sizeof (carsym)); + unsigned int ptrsize = (4 * nsymz); + unsigned int i; + ardata->symdefs = (carsym *) zalloc (carsym_size + stringsize + 1); + if (ardata->symdefs == NULL) { + bfd_error = no_memory; + goto oops; + } + carsyms = ardata->symdefs; + + stringbase = ((char *) ardata->symdefs) + carsym_size; + memcpy (stringbase, (char*)raw_armap + ptrsize + 4, stringsize); + + + /* OK, build the carsyms */ + for (i = 0; i < nsymz; i++) + { + rawptr = raw_armap + i + 1; + carsyms->file_offset = *rawptr; + carsyms->name = stringbase; + for (; *(stringbase++);); + carsyms++; + } + *stringbase = 0; + } + ardata->symdef_count = *raw_armap; + ardata->first_file_filepos = bfd_tell (abfd); + /* Pad to an even boundary if you have to */ + ardata->first_file_filepos += (ardata->first_file_filepos) %2; + free (raw_armap); + free (mapdata); + bfd_has_map (abfd) = true; + return true; +} + + +/** Extended name table. + + Normally archives support only 14-character filenames. Intel has extended + the format: longer names are stored in a special element (the first in the + archive, or second if there is an armap); the name in the ar_hdr is replaced + by . Index is the P.R. of an int (radix: + 8). */ + +/* Returns false on error, true otherwise */ +boolean +_bfd_slurp_extended_name_table (abfd) + bfd *abfd; +{ + char nextname[17]; + struct areltdata *namedata; + + if (bfd_read ((void *)nextname, 1, 16, abfd) == 16) { + + bfd_seek (abfd, -16L, SEEK_CUR); + + if (strncmp (nextname, "ARFILENAMES/ ", 16)) { + bfd_ardata (abfd)->extended_names = NULL; + return true; + } + + namedata = snarf_ar_hdr (abfd); + if (namedata == NULL) return false; + + + bfd_ardata (abfd)->extended_names = zalloc (namedata->parsed_size); + if (bfd_ardata (abfd)->extended_names == NULL) { + bfd_error = no_memory; + byebye: + free (namedata); + return false; + } + + if (bfd_read ((void*)bfd_ardata (abfd)->extended_names, 1, + namedata->parsed_size, abfd) != namedata->parsed_size) { + bfd_error = malformed_archive; + free (bfd_ardata (abfd)->extended_names); + bfd_ardata (abfd)->extended_names = NULL; + goto byebye; + } + + /* Pad to an even boundary if you have to */ + bfd_ardata (abfd)->first_file_filepos = bfd_tell (abfd); + bfd_ardata (abfd)->first_file_filepos += + (bfd_ardata (abfd)->first_file_filepos) %2; + + free (namedata); +} + return true; +} + +static +char *normalize(file) +char *file; +{ + char * filename = strrchr(file, '/'); + if (filename != (char *)NULL) { + filename ++; + } + else { + filename = file; + } +return filename; +} + +/* Follows archive_head and produces an extended name table if necessary. + Returns (in tabloc) a pointer to an extended name table, and in tablen + the length of the table. If it makes an entry it clobbers the filename + so that the element may be written without further massage. + Returns true if it ran successfully, false if something went wrong. + A successful return may still involve a zero-length tablen! + */ +boolean +bfd_construct_extended_name_table (abfd, tabloc, tablen) + bfd *abfd; + char **tabloc; + unsigned int *tablen; +{ + unsigned int maxname = abfd->xvec->ar_max_namelen; + unsigned int total_namelen = 0; + bfd *current; + char *strptr; + + *tablen = 0; + + /* Figure out how long the table should be */ + for (current = abfd->archive_head; current != NULL; current = current->next){ + unsigned int thislen = strlen (normalize(current->filename)); + if (thislen > maxname) total_namelen += thislen + 1; /* leave room for \0 */ + } + + if (total_namelen == 0) return true; + + *tabloc = zalloc (total_namelen); + if (*tabloc == NULL) { + bfd_error = no_memory; + return false; + } + + *tablen = total_namelen; + strptr = *tabloc; + + for (current = abfd->archive_head; current != NULL; current = + current->next) { + char *normal =normalize( current->filename); + unsigned int thislen = strlen (normal); + if (thislen > maxname) { + strcpy (strptr, normal); + current->filename[0] = ' '; + /* We know there will always be enough room (one of the few cases + where you may safely use sprintf). */ + sprintf ((current->filename) + 1, "-%o", (unsigned) (strptr - *tabloc)); + + strptr += thislen + 1; + } + } + + return true; +} + +/** A couple of functions for creating ar_hdrs */ + +/* Takes a filename, returns an arelt_data for it, or NULL if it can't make one. + The filename must refer to a filename in the filesystem. + The filename field of the ar_hdr will NOT be initialized +*/ + +struct areltdata * +bfd_ar_hdr_from_filesystem (filename) + char *filename; +{ + struct stat status; + struct areltdata *ared; + struct ar_hdr *hdr; + char *temp, *temp1; + + + if (stat (filename, &status) != 0) { + bfd_error = system_call_error; + return NULL; + } + + ared = (struct areltdata *) zalloc (sizeof (struct ar_hdr) + + sizeof (struct areltdata)); + if (ared == NULL) { + bfd_error = no_memory; + return NULL; + } + hdr = (struct ar_hdr *) (((char *) ared) + sizeof (struct areltdata)); + + /* ar headers are space padded, not null padded! */ + temp = (char *) hdr; + temp1 = temp + sizeof (struct ar_hdr) - 2; + for (; temp < temp1; *(temp++) = ' '); + strncpy (hdr->ar_fmag, ARFMAG, 2); + + /* Goddamned sprintf doesn't permit MAXIMUM field lengths */ + sprintf ((hdr->ar_date), "%-12ld", status.st_mtime); + sprintf ((hdr->ar_uid), "%d", status.st_uid); + sprintf ((hdr->ar_gid), "%d", status.st_gid); + sprintf ((hdr->ar_mode), "%-8o", (unsigned) status.st_mode); + sprintf ((hdr->ar_size), "%-10ld", status.st_size); + /* Correct for a lossage in sprintf whereby it null-terminates. I cannot + understand how these C losers could design such a ramshackle bunch of + IO operations */ + temp = (char *) hdr; + temp1 = temp + sizeof (struct ar_hdr) - 2; + for (; temp < temp1; temp++) { + if (*temp == '\0') *temp = ' '; + } + strncpy (hdr->ar_fmag, ARFMAG, 2); + ared->parsed_size = status.st_size; + ared->arch_header = (char *) hdr; + + return ared; +} + +struct ar_hdr * +bfd_special_undocumented_glue (filename) + char *filename; +{ + + return (struct ar_hdr *) bfd_ar_hdr_from_filesystem (filename) -> arch_header; +} + + +/* Analogous to stat call */ +int +bfd_generic_stat_arch_elt (abfd, buf) + bfd *abfd; + struct stat *buf; +{ + struct ar_hdr *hdr; + char *aloser; + + if (abfd->arelt_data == NULL) { + bfd_error = invalid_operation; + return -1; + } + + hdr = arch_hdr (abfd); + +#define foo(arelt, stelt, size) \ + buf->stelt = strtol (hdr->arelt, &aloser, size); \ + if (aloser == hdr->arelt) return -1; + + foo (ar_date, st_mtime, 10); + foo (ar_uid, st_uid, 10); + foo (ar_gid, st_gid, 10); + foo (ar_mode, st_mode, 8); + foo (ar_size, st_size, 10); + + return 0; +} + +/* Don't do anything -- it'll be taken care of later */ +void +bfd_dont_truncate_arname (ignore_abfd, ignore_filename, ignore_arhdr) + bfd *ignore_abfd; + char *ignore_filename; + char *ignore_arhdr; +{ + /* FIXME -- Actually this is incorrect. If the name is short we + should insert into the header; only if it is long should we do + nothing. + + Anyway, this interacts unpleasantly with ar's quick-append option, + for now just be compatible with the old system */ + + return; +} + +void +bfd_bsd_truncate_arname (abfd, pathname, arhdr) + bfd *abfd; + char *pathname; + char *arhdr; +{ + struct ar_hdr *hdr = (struct ar_hdr *) arhdr; + int length; + char *filename = strrchr (pathname, '/'); + int maxlen = ar_maxnamelen (abfd); + + + if (filename == NULL) + filename = pathname; + else + ++filename; + + length = strlen (filename); + + if (length <= maxlen) + memcpy (hdr->ar_name, filename, length); + else { + /* pathname: meet procrustes */ + memcpy (hdr->ar_name, filename, maxlen); + length = maxlen; + } + + if (length < 16) (hdr->ar_name)[length] = ar_padchar (abfd); +} + +/* Store name into ar header. Truncates the name to fit. + 1> strip pathname to be just the basename. + 2> if it's short enuf to fit, stuff it in. + 3> If it doesn't end with .o, truncate it to fit + 4> truncate it before the .o, append .o, stuff THAT in. +*/ + +/* This is what gnu ar does. It's better but incompatible with the bsd ar. */ +void +bfd_gnu_truncate_arname (abfd, pathname, arhdr) + bfd *abfd; + char *pathname; + char *arhdr; +{ + struct ar_hdr *hdr = (struct ar_hdr *) arhdr; + int length; + char *filename = strrchr (pathname, '/'); + int maxlen = ar_maxnamelen (abfd); + + if (filename == NULL) + filename = pathname; + else + ++filename; + + length = strlen (filename); + + if (length <= maxlen) + memcpy (hdr->ar_name, filename, length); + else { /* pathname: meet procrustes */ + memcpy (hdr->ar_name, filename, maxlen); + if ((filename[length - 2] == '.') && (filename[length - 1] == 'o')) { + hdr->ar_name[maxlen - 2] = '.'; + hdr->ar_name[maxlen - 1] = 'o'; + } + length = maxlen; + } + + if (length < 16) (hdr->ar_name)[length] = ar_padchar (abfd); +} + + +PROTO (boolean, compute_and_write_armap, (bfd *arch, unsigned int elength)); + +/* The bfd is open for write and has its format set to bfd_archive */ +boolean +_bfd_write_archive_contents (arch) + bfd *arch; +{ + bfd *current; + char *etable = NULL; + unsigned int elength = 0; + boolean makemap = bfd_has_map (arch); + boolean hasobjects = false; /* if no .o's, don't bother to make a map */ + unsigned int i; + + + /* Verify the viability of all entries; if any of them live in the + filesystem (as opposed to living in an archive open for input) + then construct a fresh ar_hdr for them. + */ + for (current = arch->archive_head; current; current = current->next) { + if (bfd_write_p (current)) { + bfd_error = invalid_operation; + return false; + } + if (!current->arelt_data) { + current->arelt_data = + (void *) bfd_ar_hdr_from_filesystem (current->filename); + if (!current->arelt_data) return false; + + /* Put in the file name */ + + BFD_SEND (arch, _bfd_truncate_arname,(arch, + current->filename, + arch_hdr(current))); + + + } + + if (makemap) { /* don't bother if we won't make a map! */ + if ((bfd_check_format (current, bfd_object)) +#if 0 /* FIXME -- these are not set correctly */ + && ((bfd_get_file_flags (current) & HAS_SYMS)) +#endif + ) + hasobjects = true; + } + } + + if (!bfd_construct_extended_name_table (arch, &etable, &elength)) + return false; + + bfd_seek (arch, 0, SEEK_SET); + bfd_write (ARMAG, 1, SARMAG, arch); + + if (makemap && hasobjects) { + + if (compute_and_write_armap (arch, elength) != true) { + if (etable) free (etable); + return false; + } + } + + if (elength != 0) { + struct ar_hdr hdr; + + memset ((char *)(&hdr), 0, sizeof (struct ar_hdr)); + sprintf (&(hdr.ar_name[0]), "ARFILENAMES/"); + sprintf (&(hdr.ar_size[0]), "%-10d", (int) elength); + hdr.ar_fmag[0] = '`'; hdr.ar_fmag[1] = '\n'; + for (i = 0; i < sizeof (struct ar_hdr); i++) + if (((char *)(&hdr))[i] == '\0') (((char *)(&hdr))[i]) = ' '; + bfd_write (&hdr, 1, sizeof (struct ar_hdr), arch); + bfd_write (etable, 1, elength, arch); + if ((elength % 2) == 1) bfd_write ("\n", 1, 1, arch); + if (etable) free (etable); + } + + for (current = arch->archive_head; current; current = current->next) { + char buffer[DEFAULT_BUFFERSIZE]; + unsigned int remaining = arelt_size (current); + struct ar_hdr *hdr = arch_hdr(current); + /* write ar header */ + + if (bfd_write (hdr, 1, sizeof(*hdr), arch) != sizeof(*hdr)) { + syserr: + bfd_error = system_call_error; + return false; + } + if (bfd_seek (current, 0L, SEEK_SET) != 0L) goto syserr; + while (remaining) { + unsigned int amt = ((remaining <= DEFAULT_BUFFERSIZE) ? remaining : + DEFAULT_BUFFERSIZE); + + if (bfd_read (buffer, amt, 1, current) != amt) goto syserr; + if (bfd_write (buffer, amt, 1, arch) != amt) goto syserr; + remaining -= amt; + } + if ((arelt_size (current) % 2) == 1) bfd_write ("\n", 1, 1, arch); + } +return true; +} + +/* Note that the namidx for the first symbol is 0 */ + + + +boolean +compute_and_write_armap (arch, elength) + bfd *arch; + unsigned int elength; +{ + bfd *current; + file_ptr elt_no = 0; + struct orl *map; + int orl_max = 15000; /* fine initial default */ + int orl_count = 0; + int stridx = 0; /* string index */ + + /* Dunno if this is the best place for this info... */ + if (elength != 0) elength += sizeof (struct ar_hdr); + elength += elength %2 ; + + map = (struct orl *) zalloc (orl_max * sizeof (struct orl)); + if (map == NULL) { + bfd_error = no_memory; + return false; + } + + /* Map over each element */ + for (current = arch->archive_head; + current != (bfd *)NULL; + current = current->next, elt_no++) + { + if ((bfd_check_format (current, bfd_object) == true) + && ((bfd_get_file_flags (current) & HAS_SYMS))) { + asymbol **syms; + unsigned int storage; + unsigned int symcount; + unsigned int src_count; + + storage = get_symtab_upper_bound (current); + if (storage == 0) { + nosymz: + fprintf (stderr, "%s: Symflags set but there are none?\n", + bfd_get_filename (current)); + exit (1); + } + syms = (asymbol **) zalloc (storage); + if (syms == NULL) { + bfd_error = no_memory; /* FIXME -- memory leak */ + return false; + } + symcount = bfd_canonicalize_symtab (current, syms); + if (symcount == 0) goto nosymz; + + /* Now map over all the symbols, picking out the ones we want */ + for (src_count = 0; src_count flags; + if ((flags & BSF_GLOBAL) || + (flags & BSF_FORT_COMM)) { + + /* This symbol will go into the archive header */ + if (orl_count == orl_max) + { + orl_max *= 2; + map = (struct orl *) realloc ((char *) map, + orl_max * sizeof (struct orl)); + } + + (map[orl_count]).name = &((syms[src_count])->name); + (map[orl_count]).pos = elt_no; + (map[orl_count]).namidx = stridx; + + stridx += strlen ((syms[src_count])->name) + 1; + ++orl_count; + } + } + } + } + /* OK, now we have collected all the data, let's write them out */ + if (!BFD_SEND (arch, write_armap, + (arch, elength, map, orl_count, stridx))) { + free (map); + return false; + } + + free (map); + return true; +} + + + /* FIXME -- have to byte-swap this */ + +boolean +bsd_write_armap (arch, elength, map, orl_count, stridx) + bfd *arch; + unsigned int elength; + struct orl *map; + int orl_count; + int stridx; +{ + unsigned int ranlibsize = (orl_count * sizeof (struct ranlib)) + 4; + unsigned int stringsize = stridx + 4; + unsigned int mapsize = stringsize + ranlibsize; + file_ptr firstreal; + bfd *current = arch->archive_head; + int last_eltno = 0; /* last element arch seen */ + int temp; + int count; + struct ar_hdr hdr; + struct stat statbuf; + unsigned int i; + int padit = mapsize & 1; + + if (padit) mapsize ++; + + firstreal = mapsize + elength + sizeof (struct ar_hdr) + SARMAG; + + fstat (arch->iostream, &statbuf); /* FIXME -- descriptor must be open! */ + memset ((char *)(&hdr), 0, sizeof (struct ar_hdr)); + sprintf (hdr.ar_name, "__.SYMDEF"); + sprintf (hdr.ar_size, "%-10d", (int) mapsize); + sprintf (hdr.ar_date, "%ld", statbuf.st_mtime); + hdr.ar_fmag[0] = '`'; hdr.ar_fmag[1] = '\n'; + for (i = 0; i < sizeof (struct ar_hdr); i++) + if (((char *)(&hdr))[i] == '\0') (((char *)(&hdr))[i]) = ' '; + bfd_write (&hdr, 1, sizeof (struct ar_hdr), arch); + + temp = orl_count /* + 4 */; + bfd_write (&temp, 1, sizeof (temp), arch); + + for (count = 0; count < orl_count; count++) { + struct symdef outs; + struct symdef *outp = &outs; + + if ((map[count]).pos != last_eltno) { + firstreal += arelt_size (current) + sizeof (struct ar_hdr); + firstreal += firstreal % 2; + last_eltno = (map[count]).pos; + current = current->next; + } + + outs.s.string_offset = ((map[count]).namidx) +4; + outs.file_offset = firstreal; + bfd_write ((char *)outp, 1, sizeof (outs), arch); + } + + /* now write the strings themselves */ + temp = stridx + 4; + bfd_write (&temp, 1, sizeof (temp), arch); + for (count = 0; count < orl_count; count++) + bfd_write (*((map[count]).name), 1, strlen (*((map[count]).name))+1, arch); + + /* The spec sez this should be a newline. But in order to be + bug-compatible for sun's ar we use a null. */ + if (padit) + bfd_write("\0",1,1,arch); + + return true; +} + + +/* A coff armap looks like : + ARMAG + struct ar_hdr with name = '/' + number of symbols + offset of file for symbol 0 + offset of file for symbol 1 + .. + offset of file for symbol n-1 + symbol name 0 + symbol name 1 + .. + symbol name n-1 + +*/ + +boolean +coff_write_armap (arch, elength, map, orl_count, stridx) + bfd *arch; + unsigned int elength; + struct orl *map; + int orl_count; + int stridx; +{ + unsigned int ranlibsize = (orl_count * 4) + 4; + unsigned int stringsize = stridx; + unsigned int mapsize = stringsize + ranlibsize; + file_ptr archive_member_file_ptr; + bfd *current = arch->archive_head; + int last_eltno = 0; /* last element arch seen */ + int count; + struct ar_hdr hdr; + struct stat statbuf; + unsigned int i; + int padit = mapsize & 1; + + if (padit) mapsize ++; + + archive_member_file_ptr = + mapsize + elength + sizeof (struct ar_hdr) + SARMAG; + + fstat (arch->iostream, &statbuf); /* FIXME -- descriptor must be open! */ + memset ((char *)(&hdr), 0, sizeof (struct ar_hdr)); + hdr.ar_name[0] = '/'; + sprintf (hdr.ar_size, "%-10d", (int) mapsize); + sprintf (hdr.ar_date, "%ld", statbuf.st_mtime); + hdr.ar_fmag[0] = '`'; hdr.ar_fmag[1] = '\n'; + + for (i = 0; i < sizeof (struct ar_hdr); i++) + if (((char *)(&hdr))[i] == '\0') (((char *)(&hdr))[i]) = ' '; + + /* Write the ar header for this item and the number of symbols */ + + bfd_write (&hdr, 1, sizeof (struct ar_hdr), arch); + bfd_write (&orl_count, 1, sizeof (orl_count), arch); + + /* Two passes, first write the file offsets for each symbol - + remembering that each offset is on a two byte boundary + */ + + for (count = 0; count < orl_count; count++) { + while ((map[count]).pos != last_eltno) { + /* If this is the first time we've seen a ref to this archive + then remember it's size */ + archive_member_file_ptr += + arelt_size (current) + sizeof (struct ar_hdr); + archive_member_file_ptr += archive_member_file_ptr % 2; + current = current->next; + last_eltno++; + } + bfd_write (&archive_member_file_ptr, + 1, + sizeof (archive_member_file_ptr), + arch); + } + + /* now write the strings themselves */ + for (count = 0; count < orl_count; count++) { + bfd_write (*((map[count]).name), + 1, + strlen (*((map[count]).name))+1, arch); + + } + /* The spec sez this should be a newline. But in order to be + bug-compatible for arc960 we use a null. */ + if (padit) + bfd_write("\0",1,1,arch); + + return true; +} diff --git a/bfd/archures.c b/bfd/archures.c new file mode 100644 index 00000000000..b7fdaf90359 --- /dev/null +++ b/bfd/archures.c @@ -0,0 +1,368 @@ +/* BFD library support routines for architectures. */ + +/* Copyright (C) 1990, 1991 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Diddler. + +BFD 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 1, or (at your option) +any later version. + +BFD 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 BFD; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* $Id$ */ + +#include "sysdep.h" +#include "bfd.h" +#include "archures.h" + +static char *prt_num_mach (); +static boolean scan_num_mach (); +static char *prt_960_mach (); +static boolean scan_960_mach (); + +struct arch_print { + enum bfd_architecture arch; + char *astr; + char *(*mach_print)(); + boolean (*mach_scan)(); +} arch_print[] = { + + {bfd_arch_unknown, "unknown", prt_num_mach, scan_num_mach}, + {bfd_arch_obscure, "obscure", prt_num_mach, scan_num_mach}, + {bfd_arch_m68k, "m68k", prt_num_mach, scan_num_mach}, + {bfd_arch_vax, "vax", prt_num_mach, scan_num_mach}, + {bfd_arch_i960, "i960", prt_960_mach, scan_960_mach}, + {bfd_arch_a29k, "a29k", prt_num_mach, scan_num_mach}, + {bfd_arch_sparc, "sparc", prt_num_mach, scan_num_mach}, + {bfd_arch_mips, "mips", prt_num_mach, scan_num_mach}, + {bfd_arch_i386, "i386", prt_num_mach, scan_num_mach}, + {bfd_arch_ns32k, "ns32k", prt_num_mach, scan_num_mach}, + {bfd_arch_tahoe, "tahoe", prt_num_mach, scan_num_mach}, + {bfd_arch_i860, "i860", prt_num_mach, scan_num_mach}, + {bfd_arch_romp, "romp", prt_num_mach, scan_num_mach}, + {bfd_arch_alliant, "alliant", prt_num_mach, scan_num_mach}, + {bfd_arch_convex, "convex", prt_num_mach, scan_num_mach}, + {bfd_arch_m88k, "m88k", prt_num_mach, scan_num_mach}, + {bfd_arch_pyramid, "pyramid", prt_num_mach, scan_num_mach}, + {bfd_arch_unknown, (char *)0, prt_num_mach, scan_num_mach}, +}; + +/* Return a printable string representing the architecture and machine + type. The result is only good until the next call to + bfd_printable_arch_mach. */ + +char * +bfd_printable_arch_mach (arch, machine) + enum bfd_architecture arch; + unsigned long machine; +{ + struct arch_print *ap; + + for (ap = arch_print; ap->astr; ap++) { + if (ap->arch == arch) { + if (machine == 0) + return ap->astr; + return (*ap->mach_print)(ap, machine); + } + } + return "UNKNOWN!"; +} + +static char * +prt_num_mach (ap, machine) + struct arch_print *ap; + unsigned long machine; +{ + static char result[20]; + + sprintf(result, "%s:%ld", ap->astr, (long) machine); + return result; +} + +/* Scan a string and attempt to turn it into an archive and machine type + combination. */ + +boolean +bfd_scan_arch_mach (string, archp, machinep) + char *string; + enum bfd_architecture *archp; + unsigned long *machinep; +{ + struct arch_print *ap; + int len; + + /* First look for an architecture, possibly followed by machtype. */ + for (ap = arch_print; ap->astr; ap++) { + if (ap->astr[0] != string[0]) + continue; + len = strlen (ap->astr); + if (!strncmp (ap->astr, string, len)) { + /* We found the architecture, now see about the machine type */ + if (archp) + *archp = ap->arch; + if (string[len] != '\0') { + if (ap->mach_scan (string+len, ap, archp, machinep, 1)) + return true; + } + if (machinep) + *machinep = 0; + return true; + } + } + + /* Couldn't find an architecture -- try for just a machine type */ + for (ap = arch_print; ap->astr; ap++) { + if (ap->mach_scan (string, ap, archp, machinep, 0)) + return true; + } + + return false; +} + +static boolean +scan_num_mach (string, ap, archp, machinep, archspec) + char *string; + struct arch_print *ap; + enum bfd_architecture *archp; + unsigned long *machinep; + int archspec; +{ + enum bfd_architecture arch; + unsigned long machine; + char achar; + + if (archspec) { + + /* Architecture already specified, now go for machine type. */ + if (string[0] != ':') + return false; + /* We'll take any valid number that occupies the entire string */ + if (1 != sscanf (string+1, "%lu%c", &machine, &achar)) + return false; + arch = ap->arch; + + } else { + + /* We couldn't identify an architecture prefix. Perhaps the entire + thing is a machine type. Be a lot picker. */ + if (1 != sscanf (string, "%lu%c", &machine, &achar)) + return false; + switch (machine) { + case 68010: + case 68020: + case 68030: + case 68040: + case 68332: + case 68050: arch = bfd_arch_m68k; break; + case 68000: arch = bfd_arch_m68k; machine = 0; break; + + case 80960: + case 960: arch = bfd_arch_i960; machine = 0; break; + + case 386: + case 80386: arch = bfd_arch_i386; machine = 0; break; + case 486: arch = bfd_arch_i386; break; + + case 29000: arch = bfd_arch_a29k; machine = 0; break; + + case 32016: + case 32032: + case 32132: + case 32232: + case 32332: + case 32432: + case 32532: arch = bfd_arch_ns32k; break; + case 32000: arch = bfd_arch_ns32k; machine = 0; break; + + case 860: + case 80860: arch = bfd_arch_i860; machine = 0; break; + + default: return false; + } + } + + if (archp) + *archp = arch; + if (machinep) + *machinep = machine; + return true; +} + +/* Intel 960 machine variants. */ + +static char * +prt_960_mach (ap, machine) + struct arch_print *ap; + unsigned long machine; +{ + static char result[20]; + char *str; + + switch (machine) { + case bfd_mach_i960_core: str = "core"; break; + case bfd_mach_i960_kb_sb: str = "kb"; break; + case bfd_mach_i960_mc: str = "mc"; break; + case bfd_mach_i960_xa: str = "xa"; break; + case bfd_mach_i960_ca: str = "ca"; break; + case bfd_mach_i960_ka_sa: str = "ka"; break; + default: + return prt_num_mach (ap, machine); + } + sprintf (result, "%s:%s", ap->astr, str); + return result; +} + +static boolean +scan_960_mach (string, ap, archp, machinep, archspec) + char *string; + struct arch_print *ap; + enum bfd_architecture *archp; + unsigned long *machinep; + int archspec; +{ + unsigned long machine; + + if (!archspec) + return false; + if (string[0] != ':') + return false; + string++; + if (string[0] == '\0') + return false; + if (string[0] == 'c' && string[1] == 'o' && string[2] == 'r' && + string[3] == 'e' && string[4] == '\0') + machine = bfd_mach_i960_core; + else if (string[1] == '\0' || string[2] != '\0') /* rest are 2-char */ + return false; + else if (string[0] == 'k' && string[1] == 'b') + machine = bfd_mach_i960_kb_sb; + else if (string[0] == 's' && string[1] == 'b') + machine = bfd_mach_i960_kb_sb; + else if (string[0] == 'm' && string[1] == 'c') + machine = bfd_mach_i960_mc; + else if (string[0] == 'x' && string[1] == 'a') + machine = bfd_mach_i960_xa; + else if (string[0] == 'c' && string[1] == 'a') + machine = bfd_mach_i960_ca; + else if (string[0] == 'k' && string[1] == 'a') + machine = bfd_mach_i960_ka_sa; + else if (string[0] == 's' && string[1] == 'a') + machine = bfd_mach_i960_ka_sa; + else + return false; + + if (archp) + *archp = ap->arch; + if (machinep) + *machinep = machine; + return true; +} + + + +/* Determine whether two BFDs' architectures and machine types are + compatible. Return merged architecture and machine type if nonnull + pointers. */ + +boolean +bfd_arch_compatible (abfd, bbfd, archp, machinep) + bfd *abfd; + bfd *bbfd; + enum bfd_architecture *archp; + unsigned long *machinep; +{ + enum bfd_architecture archa, archb; + unsigned long macha, machb; + int pick_a; + + archa = bfd_get_architecture (abfd); + archb = bfd_get_architecture (bbfd); + macha = bfd_get_machine (abfd); + machb = bfd_get_machine (bbfd); + + if (archb == bfd_arch_unknown) + pick_a = 1; + else if (archa == bfd_arch_unknown) + pick_a = 0; + else if (archa != archb) + return false; /* Not compatible */ + else { + /* Architectures are the same. Check machine types. */ + if (macha == machb) /* Same machine type */ + pick_a = 1; + else if (machb == 0) /* B is default */ + pick_a = 1; + else if (macha == 0) /* A is default */ + pick_a = 0; + else switch (archa) { + /* If particular machine types of one architecture are not + compatible with each other, this is the place to put those tests + (returning false if incompatible). */ + case bfd_arch_i960: + /* The i960 has to distinct subspecies which may not interbreed: + CORE CA + CORE KA KB MC + Any architecture on the same line is compatible, the one on + the right is the least restrictive. + */ + /* So, if either is a ca then the other must be a be core or ca */ + if (macha == bfd_mach_i960_ca) { + if (machb != bfd_mach_i960_ca && + machb != bfd_mach_i960_core) { + return false; + } + pick_a = 1; + } + else if (machb == bfd_mach_i960_ca) { + if (macha != bfd_mach_i960_ca && + macha != bfd_mach_i960_core) { + return false; + } + pick_a = 0; + } + else { + /* This must be from the bottom row, so take the higest */ + pick_a = (macha > machb); + } + + + + break; + + /* For these chips, as far as we care, "lower" numbers are included + by "higher" numbers, e.g. merge 68010 and 68020 into 68020, + 386 and 486 into 486, etc. This will need to change + if&when we care about things like 68332. */ + case bfd_arch_m68k: + case bfd_arch_ns32k: + case bfd_arch_i386: + pick_a = (macha > machb); + break; + + /* By default, pick first file's type, for lack of something better. */ + default: + pick_a = 1; + } + } + + /* Set result based on our pick */ + if (!pick_a) { + archa = archb; + macha = machb; + } + if (archp) + *archp = archa; + if (machinep) + *machinep = macha; + + return true; +} diff --git a/bfd/archures.h b/bfd/archures.h new file mode 100755 index 00000000000..b1f55941f52 --- /dev/null +++ b/bfd/archures.h @@ -0,0 +1,41 @@ +/* Intel 960 machine types */ + +/* Copyright (C) 1990, 1991 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Diddler. + +BFD 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 1, or (at your option) +any later version. + +BFD 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 BFD; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + Machine architecture and type definitions for BFD. + + These definitions are only used inside the BFD package. External programs + access them by calling bfd_scan_arch_mach() and bfd_arch_mach_string(). + + The architectures themselves are defined in bfd.h since they are an + enum needed for BFD structs. Numeric machine types are simply used + as-is, e.g. 68020. Non-numeric machine types like "i960CA" have + names in this file. */ + + +/* $Id$ */ + +#define bfd_mach_i960_core 1 +#define bfd_mach_i960_kb_sb 2 +#define bfd_mach_i960_mc 3 +#define bfd_mach_i960_xa 4 +#define bfd_mach_i960_ca 5 +#define bfd_mach_i960_ka_sa 6 + diff --git a/bfd/bfd.c b/bfd/bfd.c new file mode 100644 index 00000000000..d93bc72fe84 --- /dev/null +++ b/bfd/bfd.c @@ -0,0 +1,882 @@ + /* -*- C -*- */ + +/*** bfd -- binary file diddling routines by Gumby Wallace of Cygnus Support. + Every definition in this file should be exported and declared + in bfd.c. If you don't want it to be user-visible, put it in + libbfd.c! +*/ + +/* Copyright (C) 1990, 1991 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Diddler. + +BFD 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 1, or (at your option) +any later version. + +BFD 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 BFD; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* $Id$ */ +#include "sysdep.h" +#include "bfd.h" +#include "libbfd.h" + +short _bfd_host_big_endian = 0x0100; + /* Accessing the above as (*(char*)&_bfd_host_big_endian), will + * return 1 if the host is big-endian, 0 otherwise. + * (See HOST_IS_BIG_ENDIAN_P in bfd.h.) + */ + + + + +/** Error handling + o - Most functions return nonzero on success (check doc for + precise semantics); 0 or NULL on error. + o - Internal errors are documented by the value of bfd_error. + If that is system_call_error then check errno. + o - The easiest way to report this to the user is to use bfd_perror. +*/ + +bfd_ec bfd_error = no_error; + +char *bfd_errmsgs[] = {"No error", + "System call error", + "Invalid target", + "File in wrong format", + "Invalid operation", + "Memory exhausted", + "No symbols", + "No relocation info", + "No more archived files", + "Malformed archive", + "Symbol not found", + "File format not recognized", + "File format is ambiguous", + "Section has no contents", + "#" + }; + +#if !defined(ANSI_LIBRARIES) +char * +strerror (code) + int code; +{ + extern int sys_nerr; + extern char *sys_errlist[]; + + return (((code < 0) || (code >= sys_nerr)) ? "(unknown error)" : + sys_errlist [code]); +} +#endif /* not ANSI_LIBRARIES */ + +char * +bfd_errmsg (error_tag) + bfd_ec error_tag; +{ + extern int errno; + + if (error_tag == system_call_error) + return strerror (errno); + + if ((((int)error_tag <(int) no_error) || + ((int)error_tag > (int)invalid_error_code))) + error_tag = invalid_error_code;/* sanity check */ + + return bfd_errmsgs [(int)error_tag]; +} + +void +bfd_perror (message) + char *message; +{ + if (bfd_error == system_call_error) + perror(message); /* must be system error then... */ + else { + if (message == NULL || *message == '\0') + fprintf (stderr, "%s\n", bfd_errmsg (bfd_error)); + else + fprintf (stderr, "%s: %s\n", message, bfd_errmsg (bfd_error)); + } +} + +/* for error messages */ +char * +bfd_format_string (format) + bfd_format format; +{ + if (((int)format <(int) bfd_unknown) || ((int)format >=(int) bfd_type_end)) return "invalid"; + + switch (format) { + case bfd_object: return "object"; /* linker/assember/compiler output */ + case bfd_archive: return "archive"; /* object archive file */ + case bfd_core: return "core"; /* core dump */ + default: return "unknown"; + } +} + +/** Target configurations */ + +extern bfd_target *target_vector[]; + +/* Returns a pointer to the transfer vector for the object target + named target_name. If target_name is NULL, chooses the one in the + environment variable GNUTARGET; if that is null or not defined then + the first entry in the target list is chosen. Passing in the + string "default" or setting the environment variable to "default" + will cause the first entry in the target list to be returned. */ + +bfd_target * +bfd_find_target (target_name) + char *target_name; +{ + bfd_target **target; + extern char *getenv (); + char *targname = (target_name ? target_name : getenv ("GNUTARGET")); + + /* This is safe; the vector cannot be null */ + if (targname == NULL || !strcmp (targname, "default")) + return target_vector[0]; + + for (target = &target_vector[0]; *target != NULL; target++) { + if (!strcmp (targname, (*target)->name)) + return *target; + } + + bfd_error = invalid_target; + return NULL; +} + +/* Returns a freshly-consed, NULL-terminated vector of the names of all the + valid bfd targets. Do not modify the names */ + +char ** +bfd_target_list () +{ + int vec_length= 0; + bfd_target **target; + char **name_list, **name_ptr; + + for (target = &target_vector[0]; *target != NULL; target++) + vec_length++; + + name_ptr = name_list = (char **) zalloc ((vec_length + 1) * sizeof (char **)); + + if (name_list == NULL) { + bfd_error = no_memory; + return NULL; + } + + for (target = &target_vector[0]; *target != NULL; target++) + *(name_ptr++) = (*target)->name; + + return name_list; +} + +/** Init a bfd for read of the proper format. + */ + +/* We should be able to find out if the target was defaulted or user-specified. + If the user specified the target explicitly then we should do no search. + I guess the best way to do this is to pass an extra argument which specifies + the DWIM. */ + +/* I have chanegd this always to set the filepos to the origin before + guessing. -- Gumby, 14 Februar 1991*/ + +boolean +bfd_check_format (abfd, format) + bfd *abfd; + bfd_format format; +{ +#if obsolete + file_ptr filepos; +#endif + bfd_target **target, *save_targ, *right_targ; + int match_count; + + if (!bfd_read_p (abfd) || + ((int)(abfd->format) < (int)bfd_unknown) || + ((int)(abfd->format) >= (int)bfd_type_end)) { + bfd_error = invalid_operation; + return false; + } + + if (abfd->format != bfd_unknown) return (abfd->format == format) ? true:false; + + /* presume the answer is yes */ + abfd->format = format; + +#if obsolete + filepos = bfd_tell (abfd); +#endif + bfd_seek (abfd, (file_ptr)0, SEEK_SET); /* instead, rewind! */ + + + right_targ = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd)); + if (right_targ) { + abfd->xvec = right_targ; /* Set the target as returned */ + return true; /* File position has moved, BTW */ + } + + /* This isn't a file in the specified or defaulted target type. + See if we recognize it for any other target type. (We check them + all to make sure it's uniquely recognized.) */ + + save_targ = abfd->xvec; + match_count = 0; + right_targ = 0; + + for (target = target_vector; *target != NULL; target++) { + bfd_target *temp; + + abfd->xvec = *target; /* Change BFD's target temporarily */ +#if obsolete + bfd_seek (abfd, filepos, SEEK_SET); /* Restore original file position */ +#endif + bfd_seek (abfd, (file_ptr)0, SEEK_SET); + temp = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd)); + if (temp) { /* This format checks out as ok! */ + right_targ = temp; + match_count++; + } + } + + if (match_count == 1) { + abfd->xvec = right_targ; /* Change BFD's target permanently */ + return true; /* File position has moved, BTW */ + } + + abfd->xvec = save_targ; /* Restore original target type */ + abfd->format = bfd_unknown; /* Restore original format */ + bfd_error = ((match_count == 0) ? file_not_recognized : + file_ambiguously_recognized); +#if obsolete + bfd_seek (abfd, filepos, SEEK_SET); /* Restore original file position */ +#endif + return false; +} + +boolean +bfd_set_format (abfd, format) + bfd *abfd; + bfd_format format; +{ + file_ptr filepos; + + if (bfd_read_p (abfd) || + ((int)abfd->format < (int)bfd_unknown) || + ((int)abfd->format >= (int)bfd_type_end)) { + bfd_error = invalid_operation; + return false; + } + + if (abfd->format != bfd_unknown) return (abfd->format == format) ? true:false; + + /* presume the answer is yes */ + abfd->format = format; + + filepos = bfd_tell (abfd); + + if (!BFD_SEND_FMT (abfd, _bfd_set_format, (abfd))) { + abfd->format = bfd_unknown; + bfd_seek (abfd, filepos, SEEK_SET); + return false; + } + + return true; +} + +/* Hack object and core file sections */ + +sec_ptr +bfd_get_section_by_name (abfd, name) + bfd *abfd; + char *name; +{ + asection *sect; + + for (sect = abfd->sections; sect != NULL; sect = sect->next) + if (!strcmp (sect->name, name)) return sect; + return NULL; +} + +/* If you try to create a section with a name which is already in use, + returns the old section by that name instead. */ +sec_ptr +bfd_make_section (abfd, name) + bfd *abfd; + char *name; +{ + asection *newsect; + asection ** prev = &abfd->sections; + asection * sect = abfd->sections; + + if (abfd->output_has_begun) { + bfd_error = invalid_operation; + return NULL; + } + + while (sect) { + if (!strcmp(sect->name, name)) return sect; + prev = §->next; + sect = sect->next; + } + + newsect = (asection *) zalloc (sizeof (asection)); + if (newsect == NULL) { + bfd_error = no_memory; + return NULL; + } + + newsect->name = name; + newsect->index = abfd->section_count++; + newsect->flags = SEC_NO_FLAGS; + +#if ignore /* the compiler doesn't know that zalloc clears the storage */ + newsect->userdata = 0; + newsect->next = (asection *)NULL; + newsect->relocation = (arelent *)NULL; + newsect->reloc_count = 0; + newsect->line_filepos =0; +#endif + if (BFD_SEND (abfd, _new_section_hook, (abfd, newsect)) != true) { + free (newsect); + return NULL; + } + + *prev = newsect; + return newsect; +} + +/* Call operation on each section. Operation gets three args: the bfd, + the section, and a void * pointer (whatever the user supplied). */ + +/* This is attractive except that without lexical closures its use is hard + to make reentrant. */ +/*VARARGS2*/ +void +bfd_map_over_sections (abfd, operation, user_storage) + bfd *abfd; + void (*operation)(); + void *user_storage; +{ + asection *sect; + int i = 0; + + for (sect = abfd->sections; sect != NULL; i++, sect = sect->next) + (*operation) (abfd, sect, user_storage); + + if (i != abfd->section_count) /* Debugging */ + abort(); +} + +boolean +bfd_set_section_flags (abfd, section, flags) + bfd *abfd; + sec_ptr section; + flagword flags; +{ + if ((flags & bfd_applicable_section_flags (abfd)) != flags) { + bfd_error = invalid_operation; + return false; + } + + section->flags = flags; +return true; +} + + +boolean +bfd_set_section_size (abfd, ptr, val) + bfd *abfd; + sec_ptr ptr; + unsigned long val; +{ + /* Once you've started writing to any section you cannot create or change + the size of any others. */ + + if (abfd->output_has_begun) { + bfd_error = invalid_operation; + return false; + } + + ptr->size = val; + + return true; +} + +boolean +bfd_set_section_contents (abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; +void *location; + file_ptr offset; + int count; +{ + if (!(bfd_get_section_flags(abfd, section) & + SEC_HAS_CONTENTS)) { + bfd_error = no_contents; + return(false); + } /* if section has no contents */ + + if (BFD_SEND (abfd, _bfd_set_section_contents, + (abfd, section, location, offset, count))) { + abfd->output_has_begun = true; + return true; + } + + return false; +} + +boolean +bfd_get_section_contents (abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + void *location; + file_ptr offset; + int count; +{ + if (section->flags & SEC_CONSTRUCTOR) { + memset(location, 0, count); + return true; + } + else { + return (BFD_SEND (abfd, _bfd_get_section_contents, + (abfd, section, location, offset, count))); + } +} + + +/** Some core file info commands */ + +/* Returns a read-only string explaining what program was running when + it failed. */ + +char * +bfd_core_file_failing_command (abfd) + bfd *abfd; +{ + if (abfd->format != bfd_core) { + bfd_error = invalid_operation; + return NULL; + } + return BFD_SEND (abfd, _core_file_failing_command, (abfd)); +} + +int +bfd_core_file_failing_signal (abfd) + bfd *abfd; +{ + if (abfd->format != bfd_core) { + bfd_error = invalid_operation; + return NULL; + } + return BFD_SEND (abfd, _core_file_failing_signal, (abfd)); +} + +boolean +core_file_matches_executable_p (core_bfd, exec_bfd) + bfd *core_bfd, *exec_bfd; +{ + if ((core_bfd->format != bfd_core) || (exec_bfd->format != bfd_object)) { + bfd_error = wrong_format; + return false; + } + + return BFD_SEND (core_bfd, _core_file_matches_executable_p, (core_bfd, exec_bfd)); +} + +/** Symbols */ + +boolean +bfd_set_symtab (abfd, location, symcount) + bfd *abfd; + asymbol **location; + unsigned int symcount; +{ + if ((abfd->format != bfd_object) || (bfd_read_p (abfd))) { + bfd_error = invalid_operation; + return false; + } + + bfd_get_outsymbols (abfd) = location; + bfd_get_symcount (abfd) = symcount; + return true; +} + +/* returns the number of octets of storage required */ +unsigned int +get_reloc_upper_bound (abfd, asect) + bfd *abfd; + sec_ptr asect; +{ + if (abfd->format != bfd_object) { + bfd_error = invalid_operation; + return 0; + } + + return BFD_SEND (abfd, _get_reloc_upper_bound, (abfd, asect)); +} + +unsigned int +bfd_canonicalize_reloc (abfd, asect, location, symbols) + bfd *abfd; + sec_ptr asect; + arelent **location; + asymbol **symbols; +{ + if (abfd->format != bfd_object) { + bfd_error = invalid_operation; + return 0; + } + + return BFD_SEND (abfd, _bfd_canonicalize_reloc, (abfd, asect, location, symbols)); +} + +void +bfd_print_symbol_vandf(file, symbol) +void *file; +asymbol *symbol; +{ + flagword type = symbol->flags; + if (symbol->section != (asection *)NULL) + { + fprintf(file,"%08lx ", symbol->value+symbol->section->vma); + } + else + { + fprintf(file,"%08lx ", symbol->value); + } + fprintf(file,"%c%c%c%c%c%c%c", + (type & BSF_LOCAL) ? 'l':' ', + (type & BSF_GLOBAL) ? 'g' : ' ', + (type & BSF_IMPORT) ? 'i' : ' ', + (type & BSF_EXPORT) ? 'e' : ' ', + (type & BSF_UNDEFINED) ? 'u' : ' ', + (type & BSF_FORT_COMM) ? 'c' : ' ', + (type & BSF_DEBUGGING) ? 'd' :' '); + +} + + +boolean +bfd_set_file_flags (abfd, flags) + bfd *abfd; + flagword flags; +{ + if (abfd->format != bfd_object) { + bfd_error = wrong_format; + return false; + } + + if (bfd_read_p (abfd)) { + bfd_error = invalid_operation; + return false; + } + + if ((flags & bfd_applicable_file_flags (abfd)) != flags) { + bfd_error = invalid_operation; + return false; + } + + bfd_get_file_flags (abfd) = flags; +return true; +} + + +void +bfd_set_reloc (ignore_abfd, asect, location, count) + bfd *ignore_abfd; + sec_ptr asect; + arelent **location; + unsigned int count; +{ + asect->orelocation = location; + asect->reloc_count = count; +} +/* +If an output_bfd is supplied to this function the generated image +will be relocatable, the relocations are copied to the output file +after they have been changed to reflect the new state of the world. +There are two ways of reflecting the results of partial linkage in an +output file; by modifying the output data in place, and by modifying +the relocation record. Some native formats (eg basic a.out and basic +coff) have no way of specifying an addend in the relocation type, so +the addend has to go in the output data. This is no big deal since in +these formats the output data slot will always be big enough for the +addend. Complex reloc types with addends were invented to solve just +this problem. +*/ + +bfd_reloc_status_enum_type +bfd_perform_relocation(abfd, + reloc_entry, + data, + input_section, + output_bfd) +bfd *abfd; +arelent *reloc_entry; +void *data; +asection *input_section; +bfd *output_bfd; +{ + bfd_vma relocation; + bfd_reloc_status_enum_type flag = bfd_reloc_ok; + bfd_vma relocation_before; + bfd_vma mask; + bfd_vma target_mask; + bfd_vma addr = reloc_entry->address ; + bfd_vma output_base = 0; + struct rint_struct *howto = reloc_entry->howto; + asection *reloc_target_output_section; + asection *reloc_target_input_section; + asymbol *symbol; + + if (reloc_entry->sym_ptr_ptr) { + symbol = *( reloc_entry->sym_ptr_ptr); + if ((symbol->flags & BSF_UNDEFINED) && output_bfd == (bfd *)NULL) { + flag = bfd_reloc_undefined; + } + } + else { + symbol = (asymbol*)NULL; + } + + if (howto->special_function) { + bfd_reloc_status_enum_type cont; + cont = howto->special_function(abfd, + reloc_entry, + symbol, + data, + input_section); + if (cont != bfd_reloc_continue) return cont; + } + + /* + Work out which section the relocation is targetted at and the + initial relocation command value. + */ + + + if (symbol != (asymbol *)NULL){ + if (symbol->flags & BSF_FORT_COMM) { + relocation = 0; + } + else { + relocation = symbol->value; + } + if (symbol->section != (asection *)NULL) + { + reloc_target_input_section = symbol->section; + } + else { + reloc_target_input_section = (asection *)NULL; + } + } + else if (reloc_entry->section != (asection *)NULL) + { + relocation = 0; + reloc_target_input_section = reloc_entry->section; + } + else { + relocation = 0; + reloc_target_input_section = (asection *)NULL; + } + + + if (reloc_target_input_section != (asection *)NULL) { + + reloc_target_output_section = + reloc_target_input_section->output_section; + + if (output_bfd && howto->partial_inplace==false) { + output_base = 0; + } + else { + output_base = reloc_target_output_section->vma; + + } + + relocation += output_base + reloc_target_input_section->output_offset; + } + + relocation += reloc_entry->addend ; + + + if(reloc_entry->address > (bfd_vma)(input_section->size)) + { + return bfd_reloc_outofrange; + } + + + if (howto->pc_relative == true) + { + /* + Anything which started out as pc relative should end up that + way too + */ + + relocation -= + output_base + input_section->output_offset; + + } + + if (output_bfd!= (bfd *)NULL && howto->partial_inplace == false) { + /* + This is a partial relocation, and we want to apply the relocation + to the reloc entry rather than the raw data. Modify the reloc + inplace to reflect what we now know. + */ + reloc_entry->addend = relocation ; + reloc_entry->section = reloc_target_input_section; + if (reloc_target_input_section != (asection *)NULL) { + /* If we know the output section we can forget the symbol */ + reloc_entry->sym_ptr_ptr = (asymbol**)NULL; + } + reloc_entry->address += + input_section->output_offset; + } + else { + reloc_entry->addend = 0; + + + /* + Either we are relocating all the way, or we don't want to apply + the relocation to the reloc entry (probably because there isn't + any room in the output format to describe addends to relocs) + */ + relocation >>= howto->rightshift; + if (howto->bitsize == 32) { + mask = ~0; + } + else { + mask = (1L << howto->bitsize) - 1 ; + mask |= mask - 1; /* FIXME, what is this? */ + } + + relocation &= mask; + + /* Shift everything up to where it's going to be used */ + + relocation <<= howto->bitpos; + mask <<= howto->bitpos; + target_mask = ~mask; + + /* Wait for the day when all have the mask in them */ + + BFD_ASSERT(howto->mask == mask); + + + + relocation_before = relocation; + + + switch (howto->size) + { + case 0: + { + char x = bfd_getchar(abfd, (char *)data + addr); + relocation += x & mask; + bfd_putchar(abfd, + ( x & target_mask) | ( relocation & mask), + (unsigned char *) data + addr); + } + break; + + case 1: + { + short x = bfd_getshort(abfd, (bfd_byte *)data + addr); + relocation += x & mask; + bfd_putshort(abfd, ( x & target_mask) | (relocation & mask), + (unsigned char *)data + addr); + } + break; + case 2: + { + long x = bfd_getlong(abfd, (bfd_byte *) data + addr); + relocation += x & mask; + bfd_putlong(abfd, ( x & target_mask) | (relocation & mask), + (bfd_byte *)data + addr); + } + break; + case 3: + /* Do nothing */ + break; + default: + return bfd_reloc_other; + } + + /* See if important parts of the relocation were chopped to make + it fit into the relocation field. (ie are there any significant + bits left over after the masking ? */ + if ((relocation_before & target_mask) != 0 && + howto->complain_on_overflow == true) + { + /* Its ok if the bit which fell off is */ + return bfd_reloc_overflow; + } + } + + return flag; +} + +void +bfd_assert(file, line) +char *file; +int line; +{ + printf("bfd assertion fail %s:%d\n",file,line); +} + + +boolean +bfd_set_start_address(abfd, vma) +bfd *abfd; +bfd_vma vma; +{ + abfd->start_address = vma; + return true; +} + + +bfd_vma bfd_log2(x) +bfd_vma x; +{ + bfd_vma result = 0; + while ( (bfd_vma)(1<< result) < x) + result++; + return result; +} + +/* bfd_get_mtime: Return cached file modification time (e.g. as read + from archive header for archive members, or from file system if we have + been called before); else determine modify time, cache it, and + return it. */ + +long +bfd_get_mtime (abfd) + bfd *abfd; +{ + FILE *fp; + struct stat buf; + + if (abfd->mtime_set) + return abfd->mtime; + + fp = bfd_cache_lookup (abfd); + if (0 != fstat (fileno (fp), &buf)) + return 0; + + abfd->mtime_set = true; + abfd->mtime = buf.st_mtime; + return abfd->mtime; +} diff --git a/bfd/cache.c b/bfd/cache.c new file mode 100644 index 00000000000..39ffc7ac173 --- /dev/null +++ b/bfd/cache.c @@ -0,0 +1,200 @@ +/*** cache.c -- Allows you to have more bfds open than your system has fds. */ + +/* Copyright (C) 1990, 1991 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Diddler. + +BFD 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 1, or (at your option) +any later version. + +BFD 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 BFD; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* $Id$ */ +#include "sysdep.h" +#include "bfd.h" +#include "libbfd.h" + +/* These declarations should not be needed; libbfd.h's inclusion should + have handled it. + int fclose(); + int fseek(); +*/ + + +/* The maximum number of FDs opened by bfd */ +#define BFD_CACHE_MAX_OPEN 10 + +/* when this exceeds BFD_CACHE_MAX_OPEN, we get to work */ +static int open_files; + +static bfd *cache_sentinel; /* Chain of bfds with active fds we've + opened */ +static void +bfd_cache_delete(); + +bfd *bfd_last_cache; + + +static void +close_one() +{ + bfd *kill = cache_sentinel; + if (kill == 0) /* Nothing in the cache */ + return ; + + /* We can only close files that want to play this game. */ + while (!kill->cacheable) { + kill = kill->lru_prev; + if (kill == cache_sentinel) /* Nobody wants to play */ + return ; + } + + kill->where = ftell((FILE *)(kill->iostream)); + bfd_cache_delete(kill); + +} +/* Cuts the bfd abfd out of the chain in the cache */ +static void +snip (abfd) + bfd *abfd; +{ + abfd->lru_prev->lru_next = abfd->lru_next; + abfd->lru_next->lru_prev = abfd->lru_prev; + if (cache_sentinel == abfd) cache_sentinel = (bfd *)NULL; +} + +static void +bfd_cache_delete (abfd) + bfd *abfd; +{ + fclose ((FILE *)(abfd->iostream)); + snip (abfd); + abfd->iostream = NULL; + open_files--; +} + +static bfd * +insert(x,y) +bfd *x; +bfd *y; +{ + if (y) { + x->lru_next = y; + x->lru_prev = y->lru_prev; + y->lru_prev->lru_next = x; + y->lru_prev = x; + + } + else { + x->lru_prev = x; + x->lru_next = x; + } + return x; +} + + +/* Initialize a BFD by putting it on the cache LRU. */ +void +bfd_cache_init(abfd) +bfd *abfd; +{ + cache_sentinel = insert(abfd, cache_sentinel); +} + +void +bfd_cache_close(abfd) +bfd *abfd; +{ + /* If this file is open then remove from the chain */ + if (abfd->iostream) + { + bfd_cache_delete(abfd); + } +} + +/* Call the OS to open a file for this BFD. Returns the FILE * + (possibly null) that results from this operation. Sets up the + BFD so that future accesses know the file is open. */ + +FILE * +bfd_open_file (abfd) + bfd *abfd; +{ + abfd->cacheable = true; /* Allow it to be closed later. */ + if(open_files >= BFD_CACHE_MAX_OPEN) { + close_one(); + } + switch (abfd->direction) { + case read_direction: + case no_direction: + abfd->iostream = (char *) fopen(abfd->filename, "r"); + break; + case both_direction: + case write_direction: + if (abfd->opened_once == true) { + abfd->iostream = (char *) fopen(abfd->filename, "r+"); + if (!abfd->iostream) { + abfd->iostream = (char *) fopen(abfd->filename, "w+"); + } + } else { + /*open for creat */ + abfd->iostream = (char *) fopen(abfd->filename, "w"); + abfd->opened_once = true; + } + break; + } + if (abfd->iostream) { + open_files++; + bfd_cache_init (abfd); + } + + return (FILE *)(abfd->iostream); +} + +/* Find a file descriptor for this BFD. If necessary, open it. + If there are already more than BFD_CACHE_MAX_OPEN files open, try to close + one first, to avoid running out of file descriptors. */ + +FILE * +bfd_cache_lookup_worker (abfd) + bfd *abfd; +{ + if (abfd->my_archive) + { + abfd = abfd->my_archive; + } + /* Is this file already open .. if so then quick exit */ + if (abfd->iostream) + { + if (abfd != cache_sentinel) { + /* Place onto head of lru chain */ + snip (abfd); + cache_sentinel = insert(abfd, cache_sentinel); + } + } + /* This is a bfd without a stream - + so it must have been closed or never opened. + find an empty cache entry and use it. */ + else + { + + if (open_files >= BFD_CACHE_MAX_OPEN) + { + close_one(); + } + + BFD_ASSERT(bfd_open_file (abfd) != (FILE *)NULL) ; + fseek((FILE *)(abfd->iostream), abfd->where, false); + } +bfd_last_cache = abfd; + return (FILE *)(abfd->iostream); +} diff --git a/bfd/coff-code.h b/bfd/coff-code.h new file mode 100755 index 00000000000..8ec6ec25a86 --- /dev/null +++ b/bfd/coff-code.h @@ -0,0 +1,2561 @@ +/* + Copyright (C) 1990, 1991 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Diddler. + +BFD 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 1, or (at your option) any later version. + +BFD 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 + BFD; see the file COPYING. If not, write to the Free Software Foundation, + 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* $Id$ */ +/* + FIXME-SOON. There is a major, potentially invalid assumption in this + code. Namely, that incoming symbol tables will be broken up and glued back + together but only on C_FILE boundaries. That is, if you break the symbol + table on some other boundary, or if you remove a single symbol in the + middle, it is possible to end up with garbage where you expect your + debugging info to be. This only affects debugging info. Specifically, it + affects all of the foondx's in the aux entries. C_FILE entries ARE glued + back together properly. Line numbers and relocations are tracked with + pointers so their ndx's aren't affected. + +On the other hand, if the symbol that a line number or reloc points to goes + away, or isn't included in an output bfd, then you'll end up with mush + anyway. + +I'm not sure at this point, (Sun Mar 3 00:56:11 PST 1991), but I suspect the + bfd library will need to provide at least the option of a higher and/or + lower abstraction for (at least debugging) symbols. The current + abstraction is sufficient for linking, nm, and very nearly for stripping, + but is nowhere near what would be needed for gas to create coff symbols or + for gdb to read them. + +xoxorich. +*/ + +#include "archures.h" /* Machine architectures and types */ + +/* SUPPRESS 558 */ +/* SUPPRESS 590 */ +/* SUPPRESS 529 */ +/* SUPPRESS 530 */ + +#define ALIGN(this, boundary) \ + ((( (this) + ((boundary) -1)) & (~((boundary)-1)))) + +#define sp(x) bfd_h_put_x(abfd, x, &x) + + + +/* + Align an address by rounding it up to a power of two. It leaves the + address unchanged if align == 0 (2^0 = alignment of 1 byte) +*/ +#define i960_align(addr, align) \ + ( ((addr) + ((1<<(align))-1)) & (-1 << (align))) + + +/* All the swapping routines */ + +static void +swap_reloc(abfd, reloc) + bfd *abfd; + RELOC *reloc; +{ + sp(reloc->r_vaddr); + sp(reloc->r_symndx); + sp(reloc->r_type); +} + + +static void +swap_filehdr(abfd, filehdr) + bfd *abfd; + FILHDR *filehdr; +{ + sp(filehdr->f_magic); + sp(filehdr->f_nscns); + sp(filehdr->f_timdat); + sp(filehdr->f_symptr); + sp(filehdr->f_nsyms); + sp(filehdr->f_opthdr); + sp(filehdr->f_flags); + + +} + +static void +swap_aouthdr(abfd, aouthdr) + bfd *abfd; + AOUTHDR *aouthdr; +{ + + sp(aouthdr->magic); + sp(aouthdr->vstamp); + sp(aouthdr->tsize); + sp(aouthdr->dsize); + sp(aouthdr->bsize); + sp(aouthdr->entry); + sp(aouthdr->text_start); + sp(aouthdr->data_start); +#ifdef I960 + sp(aouthdr->tagentries); +#endif +} + +static void +swap_scnhdr(abfd, scnhdr) + bfd *abfd; + SCNHDR *scnhdr; +{ + sp(scnhdr->s_vaddr); + sp(scnhdr->s_paddr); + sp(scnhdr->s_size); + sp(scnhdr->s_scnptr); + sp(scnhdr->s_relptr); + sp(scnhdr->s_lnnoptr); + sp(scnhdr->s_nreloc); + sp(scnhdr->s_nlnno); + sp(scnhdr->s_flags); +#ifdef I960 + sp(scnhdr->s_align); +#endif +} + +static void +swap_name(abfd, ptr) + bfd *abfd; + long *ptr; +{ + if (ptr[0] == 0) { + /* There is an index which needs to be swapped */ + bfd_h_put_x(abfd, ptr[1], (ptr + 1)); + } + else { + /* This is a string .. leave it alone */ + } +} + +void +bfd_coff_swap_sym(abfd, se) + bfd *abfd; + SYMENT *se; +{ + swap_name(abfd, se->n_name); + bfd_h_put_x(abfd, se->n_value, &se->n_value); + bfd_h_put_x(abfd, se->n_scnum, &se->n_scnum); + bfd_h_put_x(abfd, se->n_type, &se->n_type); + bfd_h_put_x(abfd, se->n_sclass, &se->n_sclass); + bfd_h_put_x(abfd, se->n_numaux, &se->n_numaux); +} + +void +bfd_coff_swap_aux(abfd, au, type, class) + bfd *abfd; + AUXENT *au; + int type; + int class; +{ + switch (class) { + case C_FILE: + swap_name(abfd, &au->x_file.x_n); + break; + case C_STAT: +#ifdef C_LEAFSTAT + case C_LEAFSTAT: +#endif + case C_HIDDEN: + if (type == T_NULL) { + sp(au->x_scn.x_scnlen); + sp(au->x_scn.x_nreloc); + sp(au->x_scn.x_nlinno); + break; + } + default: + sp(au->x_sym.x_tagndx); + sp(au->x_sym.x_tvndx); + + if (ISARY(type) || class == C_BLOCK) { + sp(au->x_sym.x_fcnary.x_ary.x_dimen[0]); + sp(au->x_sym.x_fcnary.x_ary.x_dimen[1]); + sp(au->x_sym.x_fcnary.x_ary.x_dimen[2]); + sp(au->x_sym.x_fcnary.x_ary.x_dimen[3]); + } + else { + sp(au->x_sym.x_fcnary.x_fcn.x_lnnoptr); + sp(au->x_sym.x_fcnary.x_fcn.x_endndx); + } + if (ISFCN(type)) { + sp(au->x_sym.x_misc.x_fsize); + } + else { + sp(au->x_sym.x_misc.x_lnsz.x_lnno); + sp(au->x_sym.x_misc.x_lnsz.x_size); + } + } +} + +void +bfd_coff_swap_lineno(abfd, lineno) + bfd *abfd; + LINENO *lineno; +{ + sp(lineno->l_addr.l_symndx); + sp(lineno->l_lnno); +} + + +/* void warning(); */ +extern asection abs_section; + + + +static int +get_index(symbol) + asymbol *symbol; +{ + return (int) symbol->value; +} + +static void +set_index(symbol, idx) + asymbol *symbol; + unsigned int idx; +{ + symbol->value = idx; +} + + +/* + initialize a section structure with information peculiar to this + particular implementation of coff +*/ + +static boolean +coff_new_section_hook(abfd_ignore, section_ignore) + bfd *abfd_ignore; + asection *section_ignore; +{ + return true; +} +/* actually it makes itself and its children from the file headers */ +static boolean +make_a_section_from_file(abfd, hdr) + bfd *abfd; + struct scnhdr *hdr; + +{ + asection *return_section; + { + char *name = malloc(9); + if (name == NULL) { + bfd_error = no_memory; + return (BFD_FAILURE); + } /* on error */ + strncpy(name, (char *) &hdr->s_name[0], 8); + + return_section = bfd_make_section(abfd, name); + (return_section->name)[8] = 0; + } + + /* s_paddr is presumed to be = to s_vaddr */ +#define assign(to, from) return_section->to = hdr->from + assign(vma, s_vaddr); + /* assign (vma, s_vaddr); */ + assign(size, s_size); + assign(filepos, s_scnptr); + assign(rel_filepos, s_relptr); + assign(reloc_count, s_nreloc); +#ifdef I960 + { + + assign(alignment_power, s_align); + { + unsigned int i; + for (i = 0; i < 32; i++) { + if ((1 << i) >= (int) (return_section->alignment_power)) { + return_section->alignment_power = i; + break; + } + } + } + } +#endif + assign(line_filepos, s_lnnoptr); + /* + return_section->linesize = hdr->s_nlnno * sizeof (struct lineno); + */ + +#undef assign + return_section->lineno_count = hdr->s_nlnno; + return_section->userdata = NULL; + return_section->next = (asection *) NULL; + if ((hdr->s_flags & STYP_TEXT) || (hdr->s_flags & STYP_DATA)) + return_section->flags = (SEC_LOAD | SEC_ALLOC); + else if (hdr->s_flags & STYP_BSS) + return_section->flags = SEC_ALLOC; + + if (hdr->s_nreloc != 0) + return_section->flags |= SEC_RELOC; + if (hdr->s_scnptr != 0) + return_section->flags |= SEC_HAS_CONTENTS; + return true; +} + + +static +bfd_target * +coff_real_object_p(abfd, nscns, opthdr) + bfd *abfd; + unsigned nscns, + opthdr; +{ + struct icofdata *tdata; + char *file_info; /* buffer for all the headers */ + size_t readsize; /* length of file_info */ + struct filehdr *filehdr; /* points into file_info */ + struct scnhdr *sections; /* points into file_info */ + /* + OK, now we know the format, read in the filehdr, soi-disant "optional + header", and all the sections. + */ + readsize = sizeof(struct filehdr) + + opthdr + + (nscns * sizeof(struct scnhdr)); + + file_info = malloc(readsize); + if (file_info == NULL) { + bfd_error = no_memory; + return 0; + } + if (bfd_seek(abfd, 0L, SEEK_SET) < 0) + return 0; + if (bfd_read((void *) file_info, 1, readsize, abfd) != readsize) + return 0; + filehdr = (struct filehdr *) file_info; + sections = (struct scnhdr *) (file_info + sizeof(struct filehdr) + opthdr); + + + swap_filehdr(abfd, filehdr); + + /* Now copy data as required; construct all asections etc */ + tdata = (struct icofdata *) malloc(sizeof(struct icofdata) + + sizeof(AOUTHDR)); + if (tdata == NULL) { + bfd_error = no_memory; + return 0; + } + tdata->symbol_index_slew = 0; + tdata->relocbase =0; + tdata->raw_syment_count = 0; + tdata->raw_linenos = 0; + tdata->raw_syments = 0; + tdata->sym_filepos =0; + + if (nscns != 0) { + unsigned int i; + for (i = 0; i < nscns; i++) { + swap_scnhdr(abfd, sections + i); + make_a_section_from_file(abfd, sections + i); + } + } + /* Determine the machine architecture and type. */ + abfd->obj_machine = 0; + switch (filehdr->f_magic) { +#ifdef MC68MAGIC + case MC68MAGIC: + case MC68DMAGIC: + abfd->obj_arch = bfd_arch_m68k; + abfd->obj_machine = 68020; + break; +#endif +#ifdef I960ROMAGIC + case I960ROMAGIC: + case I960RWMAGIC: + abfd->obj_arch = bfd_arch_i960; + switch (F_I960TYPE & filehdr->f_flags) { + case F_I960CORE: + abfd->obj_machine = bfd_mach_i960_core; + break; + case F_I960KB: + abfd->obj_machine = bfd_mach_i960_kb_sb; + break; + case F_I960MC: + abfd->obj_machine = bfd_mach_i960_mc; + break; + case F_I960XA: + abfd->obj_machine = bfd_mach_i960_xa; + break; + case F_I960CA: + abfd->obj_machine = bfd_mach_i960_ca; + break; + case F_I960KA: + abfd->obj_machine = bfd_mach_i960_ka_sa; + break; + /* + Doomed to fail but sneak out a bit of info in the process. + */ + default: + abfd->obj_machine = filehdr->f_flags & F_I960TYPE; + } + break; +#endif + + default: /* Unreadable input file type */ + abfd->obj_arch = bfd_arch_obscure; + break; + } + + if (!(filehdr->f_flags & F_RELFLG)) + abfd->flags |= HAS_RELOC; + if ((filehdr->f_flags & F_EXEC)) + abfd->flags |= EXEC_P; + if (!(filehdr->f_flags & F_LNNO)) + abfd->flags |= HAS_LINENO; + if (!(filehdr->f_flags & F_LSYMS)) + abfd->flags |= HAS_LOCALS; + + abfd->tdata = (void *) tdata; + bfd_get_symcount(abfd) = filehdr->f_nsyms; + if (filehdr->f_nsyms) + abfd->flags |= HAS_SYMS; + + tdata->sym_filepos = filehdr->f_symptr; + tdata->hdr = (struct aouthdr *) (file_info + sizeof(struct filehdr)); + + swap_aouthdr(abfd, tdata->hdr); + + tdata->symbols = (coff_symbol_type *) NULL; + bfd_get_start_address(abfd) = opthdr ? exec_hdr(abfd)->entry : 0; + + return abfd->xvec; +} +static coff_symbol_type * +coff_symbol_from(abfd, symbol) + bfd *abfd; + asymbol *symbol; +{ + return symbol->the_bfd->xvec->flavour == bfd_target_coff_flavour_enum + ? + (coff_symbol_type *) symbol + : + (coff_symbol_type *) NULL; + +} + + + +static bfd_target * +coff_object_p(abfd) + bfd *abfd; +{ + unsigned short magic, + nscns, + opthdr; + bfd_error = system_call_error; + + /* figure out how much to read */ + if (bfd_read((void *) &magic, 1, sizeof(magic), abfd) != sizeof(magic)) + return 0; + + magic = bfd_h_getshort(abfd, (bfd_byte *) (&magic)); + + if (BADMAG(*((struct filehdr *) & magic))) { + bfd_error = wrong_format; + return 0; + } + if (bfd_read((void *) &nscns, 1, sizeof(nscns), abfd) != sizeof(nscns)) + return 0; + nscns = bfd_h_getshort(abfd, (unsigned char *) &nscns); + if (bfd_seek(abfd, (file_ptr) & (((struct filehdr *) NULL)->f_opthdr), SEEK_SET) + < 0) + return (bfd_target *) NULL; + if (bfd_read((void *) &opthdr, 1, sizeof(opthdr), abfd) != sizeof(opthdr)) + return (bfd_target *) NULL; + opthdr = bfd_h_getshort(abfd, (unsigned char *) &opthdr); + + return coff_real_object_p(abfd, nscns, opthdr); +} + +static boolean +coff_mkobject(abfd) + bfd *abfd; +{ + char *rawptr; + + + bfd_error = system_call_error; + + /* Use an intermediate variable for clarity */ + rawptr = malloc(sizeof(struct icofdata) + sizeof(AOUTHDR)); + if (rawptr == NULL) { + bfd_error = no_memory; + return false; + } + abfd->tdata = (void *) ((struct icofdata *) rawptr); + exec_hdr(abfd) = (AOUTHDR *) (rawptr + sizeof(struct icofdata)); + obj_relocbase(abfd) =0; + return true; +} + + + +static void +coff_count_linenumbers(abfd) + bfd *abfd; +{ + unsigned int limit = bfd_get_symcount(abfd); + unsigned int i; + asymbol **p; + { + asection *s = abfd->sections->output_section; + while (s) { + BFD_ASSERT(s->lineno_count == 0); + s = s->next; + } + } + + + for (p = abfd->outsymbols, i = 0; i < limit; i++, p++) { + asymbol *q_maybe = *p; + if (q_maybe->the_bfd->xvec->flavour == bfd_target_coff_flavour_enum) { + coff_symbol_type *q = coffsymbol(q_maybe); + if (q->lineno) { + /* + This symbol has a linenumber, increment the owning + section's linenumber count + */ + alent *l = q->lineno; + q->symbol.section->output_section->lineno_count++; + l++; + while (l->line_number) { + q->symbol.section->output_section->lineno_count++; + l++; + } + } + } + } +} + +/* + This function returns true if the supplied SYMENT has an auxent with + and endndx field which should be relocated as the symbol moves + within the file. +*/ +static +boolean +uses_x_sym_x_fcnary_x_fcn_x_endndx_p(native) +SYMENT *native; +{ + if (ISFCN(native->n_type)) + return true; + if (native->n_sclass == C_BLOCK) + return true; + if (native->n_sclass == C_STRTAG) + return true; + if (native->n_sclass == C_ENTAG) + return true; + if (native->n_sclass == C_UNTAG) + return true; + if (native->n_sclass == C_MOS) + return true; + if(native->n_sclass == C_EOS) + return true; + if(native->n_sclass == C_MOE) + return true; + return false; + +} +/* + This function returns true if the supplied SYMENT has an AUXENT with + a tagndx field which should be relocated. + + The coff book says that all auxents have this and should be moved, + but all the actual implementations I've looked at do this .. + (sac@cygnus.com) + +*/ +static boolean +uses_x_sym_x_tagndx_p(native) +SYMENT *native; +{ + if (BTYPE(native->n_type) == T_STRUCT) return true; + if (BTYPE(native->n_type) == T_UNION) return true; + if (BTYPE(native->n_type) == T_ENUM)return true; + return false; +} + + +/* + Return the canonical symbol we work out how far it has moved since it + started life. This is done by finding the base of the raw syments as + read in when a file was slurped, which discovers the original offset + into the file. Then we return the value which we've saved in the + n_offset field of that name - and voila. +*/ +static +unsigned int +new_idx(symbol, original_offset) +coff_symbol_type *symbol; +unsigned int original_offset; +{ + struct icofdata *coff = obj_icof(symbol->symbol.the_bfd); + + /* Point to the native we used to point to */ + SYMENT *native = coff->raw_syments + original_offset; + + /* We keep the native's new index in it's string space */ + return native->n_offset; +} + + +/* Function to run through the raw parts of a coff symbol table and + loads each SYMENT's n_offset with its output index. If a symbol has + been deleted or moved to the end, still mark the offset of the one + following it. This makes refs to symbols which have moved point to + the symbol which now sits in the spot vacated. +*/ + +static +void +preload_n_offset(abfd) +bfd *abfd; +{ + unsigned int limit = bfd_get_symcount(abfd); + asymbol **p = abfd->outsymbols; + bfd *thebfd = (bfd *)NULL; + unsigned int native_index; + + native_index = 0; + + /* First phase, mark each SYMENT with final position */ + while (limit --) { + coff_symbol_type *q = coff_symbol_from(abfd, *p); + if (q != (coff_symbol_type *)NULL && q->native) { + q->native->n_offset = native_index; + native_index += 1 + q->native->n_numaux; + } + else { + native_index++; + } + p++; + } + +} + + +/* + run through the internal symbol table and make all the pointers and things + within the table point to the right places +*/ + +static void +coff_mangle_symbols(abfd) + bfd *abfd; +{ + asymbol **p; + unsigned int native_index = 0; + + unsigned int last_file_index = 0; + unsigned int limit = bfd_get_symcount(abfd); + SYMENT *last_file_symbol = (SYMENT *) NULL; + + /* Remember the bfd from the last symbol */ + bfd *last_bfd = (bfd *) NULL; + /* Remember the native from the last symbol */ + SYMENT *last_native = (SYMENT *) NULL; + + + preload_n_offset(abfd); + + p = abfd->outsymbols; + limit = bfd_get_symcount(abfd); + native_index = 0; + while (limit--) + { + coff_symbol_type *q = coff_symbol_from(abfd, *p); + if ((*p)->the_bfd != last_bfd) { + last_bfd = (*p)->the_bfd; + last_native = 0; + last_file_index = native_index; + } + + if (!q) { + native_index++; + } + else { + SYMENT *native = q->native; + if (native == (SYMENT *) NULL) { + native_index++; + } + else { + + + /* Alter the native representation */ + if (q->symbol.flags & BSF_FORT_COMM) { + native->n_scnum = 0; + native->n_value = q->symbol.value; + } + else if (q->symbol.flags & BSF_DEBUGGING) { + /* native->n_scnum = -2; */ + native->n_value = q->symbol.value; + } + else if (q->symbol.flags & BSF_UNDEFINED) { + native->n_scnum = 0; + native->n_value = 0; + } + else if (q->symbol.flags & BSF_ABSOLUTE) { + native->n_scnum = -1; + native->n_value = q->symbol.value; + } + else { + native->n_scnum = q->symbol.section->output_section->index + 1; + native->n_value = + q->symbol.value + + q->symbol.section->output_offset + + q->symbol.section->output_section->vma; + } + if (native->n_numaux != 0) + { + union auxent *a = (union auxent *) (native + 1); + + /* If this symbol forward references another, put + into it the real index of it by looking around + */ + if (uses_x_sym_x_fcnary_x_fcn_x_endndx_p(native)) + { + /* If this is a FCN entry without a + following .bf then we cheat and + insert the correct value directy. + */ + if (ISFCN(native->n_type) && + (native+2)->n_sclass != C_BLOCK) { + a->x_sym.x_fcnary.x_fcn.x_endndx = + native_index+ native->n_numaux + 1; + } + else{ + a->x_sym.x_fcnary.x_fcn.x_endndx = + new_idx(q,a->x_sym.x_fcnary.x_fcn.x_endndx); + } + + + } + if (uses_x_sym_x_tagndx_p(native)) { + a->x_sym.x_tagndx = + new_idx(q,a->x_sym.x_tagndx); + } +#ifdef I960 + else if (native->n_sclass == C_FCN + || !strcmp((char *) q->symbol.name, ".bf")) { + a->x_sym.x_fcnary.x_fcn.x_endndx = 0; + } +#endif /* I960 */ + + } + switch (native->n_sclass) { + case C_MOS: + case C_EOS: + case C_REGPARM: + case C_REG: +#ifdef C_AUTOARG + case C_AUTOARG: /* 960-specific storage class */ +#endif + /* + Fix so that they have an absolute section + */ + native->n_scnum = -1; + break; + + case C_FILE: + if (last_file_symbol) { + if (last_file_symbol->n_value != 0) { + abort(); + } /* sanity assertion */ + last_file_symbol->n_value = native_index; + } /* Chain all the .file symbols together */ + last_file_symbol = native; + + break; + + case C_EXT: + if (!ISFCN(native->n_type) + && last_file_symbol != NULL) { + if (last_file_symbol->n_value != 0) { + abort(); + } /* sanity assertion */ + last_file_symbol->n_value = native_index; + last_file_symbol = NULL; + } /* This should be the first global variable. */ + break; + + case C_FCN: + case C_NULL: + case C_AUTO: + case C_EXTDEF: + case C_LABEL: + case C_ULABEL: + case C_USTATIC: + case C_STRTAG: + case C_BLOCK: + case C_STAT: +#ifdef I960 + case C_LEAFEXT: + case C_LEAFSTAT: +#endif + break; + default: + /* + Bogus: This should be returning an error code, not + printing something out! + */ + /* + warning("Unrecognised sclass %d", native->n_sclass); + */ + break; + } + native_index += 1 + native->n_numaux; + + /* Remember the last native here */ + last_native = native + native->n_numaux; + } + + } + + p++; + } + +} + + +static void +coff_write_symbols(abfd) + bfd *abfd; +{ + unsigned int i; + unsigned int limit = bfd_get_symcount(abfd); + unsigned int written = 0; + SYMENT dummy; + asymbol **p; + unsigned int string_size = 0; + + + /* Seek to the right place */ + bfd_seek(abfd, obj_sym_filepos(abfd), SEEK_SET); + + /* Output all the symbols we have */ + + written = 0; + for (p = abfd->outsymbols, i = 0; i < limit; i++, p++) { + asymbol *symbol = *p; + coff_symbol_type *c_symbol = coff_symbol_from(abfd, symbol); + + unsigned int j; + SYMENT *native; + if (c_symbol == (coff_symbol_type *) NULL || + c_symbol->native == (SYMENT *) NULL) { + /* + This symbol has been created by the loader, or come from a non + coff format. It has no native element to inherit, make our + own + */ + native = &dummy; + native->n_type = T_NULL; + if (symbol->flags & BSF_ABSOLUTE) { + native->n_scnum = N_ABS; + native->n_value = symbol->value; + } + else if (symbol->flags & (BSF_UNDEFINED | BSF_FORT_COMM)) { + native->n_scnum = N_UNDEF; + native->n_value = symbol->value; + } + else if (symbol->flags & BSF_DEBUGGING) { + /* + remove name so it doesn't take up any space + */ + symbol->name = ""; +#if 0 /* FIXME -- Steve hasn't decided what to do + with these */ + /* + Don't do anything with debugs from the loader + */ + native->n_scnum = N_DEBUG; +#endif + continue; + } + else { + native->n_scnum = symbol->section->output_section->index + 1; + native->n_value = symbol->value + + symbol->section->output_section->vma + + symbol->section->output_offset; + } + +#ifdef I960 + /* + FIXME-SOON: THIS IS ALREADY WRONG FOR I960. Should echo the + flags in the filehdr. (?) + */ + native->n_flags = 0; +#else /* else not I960 */ +#ifdef HASPAD1 + native->pad1[0] = 0; + native->pad1[0] = 0; +#endif +#endif /* I960 */ + native->pad2[0] = 0; + native->pad2[1] = 0; + + native->n_type = 0; + native->n_sclass = C_EXT; + native->n_numaux = 0; + } + else + /* + Does this symbol have an ascociated line number - if so then + make it remember this symbol index. Also tag the auxent of + this symbol to point to the right place in the lineno table + */ + { + alent *lineno = c_symbol->lineno; + native = c_symbol->native; + if (lineno) { + unsigned int count = 0; + lineno[count].u.offset = written; + if (native->n_numaux) { + union auxent *a = (union auxent *) (native + 1); + a->x_sym.x_fcnary.x_fcn.x_lnnoptr = + c_symbol->symbol.section->output_section->moving_line_filepos; + } + /* + And count and relocate all other linenumbers + */ + count++; + while (lineno[count].line_number) { + lineno[count].u.offset += + c_symbol->symbol.section->output_section->vma + + c_symbol->symbol.section->output_offset; + count++; + } + c_symbol->symbol.section->output_section->moving_line_filepos += + count * sizeof(struct lineno); + + } + } /* if symbol new to coff */ + + /* Fix the symbol names */ + { + unsigned int name_length; + if (symbol->name == (char *) NULL) { + /* + coff symbols always have names, so we'll make one up + */ + symbol->name = "strange"; + } + name_length = strlen(symbol->name); + if (name_length <= SYMNMLEN) { + /* This name will fit into the symbol neatly */ + strncpy(native->n_name, symbol->name, SYMNMLEN); + } + else { + native->n_offset = string_size + 4; + native->n_zeroes = 0; + string_size += name_length + 1; + } + { + unsigned int numaux = native->n_numaux; + int type = native->n_type; + int class = native->n_sclass; + bfd_coff_swap_sym(abfd, native); + bfd_write((void *) native, 1, SYMESZ, abfd); + for (j = 0; j != native->n_numaux; j++) { + bfd_coff_swap_aux(abfd, native + j + 1, type, class); + bfd_write((void *) (native + j + 1), 1, AUXESZ, abfd); + + } + /* + Reuse somewhere in the symbol to keep the index + */ + set_index(symbol, written); + written += 1 + numaux; + } + } + } /* for each out symbol */ + + bfd_get_symcount(abfd) = written; + /* Now write out strings */ + + if (string_size) { + unsigned int size = string_size + 4; + bfd_h_put_x(abfd, size, &size); + bfd_write((void *) &size, 1, sizeof(size), abfd); + for (p = abfd->outsymbols, i = 0; i < limit; i++, p++) { + asymbol *q = *p; + size_t name_length = strlen(q->name); + if (name_length > SYMNMLEN) { + bfd_write((void *) (q->name), 1, name_length + 1, abfd); + } + } + } + else { + /* We would normally not write anything here, but we'll write + out 4 so that any stupid coff reader which tries to read + the string table even when there isn't one won't croak. + */ + + uint32e_type size = 4; + bfd_h_put_x(abfd, size, &size); + bfd_write((void *)&size, 1, sizeof(size), abfd); + + } + +} + +static void +coff_write_relocs(abfd) + bfd *abfd; +{ + asection *s; + for (s = abfd->sections; s != (asection *) NULL; s = s->next) { + unsigned int i; + arelent **p = s->orelocation; + bfd_seek(abfd, s->rel_filepos, SEEK_SET); + for (i = 0; i < s->reloc_count; i++) { + struct reloc n; + arelent *q = p[i]; + memset(&n, 0, sizeof(n)); + n.r_vaddr = q->address + s->vma; + n.r_symndx = get_index((*(q->sym_ptr_ptr))); + n.r_type = q->howto->type; + swap_reloc(abfd, &n); + bfd_write((void *) &n, 1, RELSZ, abfd); + } + } +} +static void +coff_write_linenumbers(abfd) + bfd *abfd; +{ + asection *s; + for (s = abfd->sections; s != (asection *) NULL; s = s->next) { + if (s->lineno_count) { + asymbol **q = abfd->outsymbols; + bfd_seek(abfd, s->line_filepos, SEEK_SET); + /* Find all the linenumbers in this section */ + while (*q) { + asymbol *p = *q; + alent *l = BFD_SEND(p->the_bfd, _get_lineno, (p->the_bfd, p)); + if (l) { + /* Found a linenumber entry, output */ + struct lineno out; + out.l_lnno = 0; + out.l_addr.l_symndx = l->u.offset; +#ifdef LINENO_PADDING + out.padding[0] = 0; + out.padding[1] = 0; +#endif + bfd_coff_swap_lineno(abfd, &out); + bfd_write((void *) &out, 1, LINESZ, abfd); + l++; + while (l->line_number) { + out.l_lnno = l->line_number; + out.l_addr.l_symndx = l->u.offset; + bfd_coff_swap_lineno(abfd, &out); + bfd_write((void *) &out, 1, LINESZ, abfd); + l++; + } + } + q++; + } + } + } +} + + +static asymbol * +coff_make_empty_symbol(abfd) + bfd *abfd; +{ + coff_symbol_type *new = (coff_symbol_type *) malloc(sizeof(coff_symbol_type)); + if (new == NULL) { + bfd_error = no_memory; + return (NULL); + } /* on error */ + new->native = 0; + new->lineno = (alent *) NULL; + new->symbol.the_bfd = abfd; + return &new->symbol; +} + +static void +coff_print_symbol(ignore_abfd, file, symbol, how) + bfd *ignore_abfd; + FILE *file; + asymbol *symbol; + bfd_print_symbol_enum_type how; +{ + switch (how) { + case bfd_print_symbol_name_enum: + fprintf(file, "%s", symbol->name); + break; + case bfd_print_symbol_type_enum: + fprintf(file, "coff %lx %lx", (unsigned long) coffsymbol(symbol)->native, + (unsigned long) coffsymbol(symbol)->lineno); + break; + case bfd_print_symbol_all_enum: + { + char *section_name = symbol->section == (asection *) NULL ? + "*abs" : symbol->section->name; + bfd_print_symbol_vandf((void *) file, symbol); + + fprintf(file, " %-5s %s %s %s", + section_name, + coffsymbol(symbol)->native ? "n" : "g", + coffsymbol(symbol)->lineno ? "l" : " ", + symbol->name); + } + + + break; + } +} +static alent * +coff_get_lineno(ignore_abfd, symbol) + bfd *ignore_abfd; + asymbol *symbol; +{ + return coffsymbol(symbol)->lineno; +} +/* + Set flags and magic number of a coff file from architecture and machine + type. Result is true if we can represent the arch&type, false if not. +*/ +static boolean +coff_set_flags(abfd, magicp, flagsp) + bfd *abfd; + unsigned *magicp, + *flagsp; +{ + + + switch (abfd->obj_arch) { + +#ifdef I960ROMAGIC + + case bfd_arch_i960: + + { + unsigned flags; + *magicp = I960ROMAGIC; + /* + ((bfd_get_file_flags(abfd) & WP_TEXT) ? I960ROMAGIC : + I960RWMAGIC); FIXME??? + */ + switch (abfd->obj_machine) { + case bfd_mach_i960_core: + flags = F_I960CORE; + break; + case bfd_mach_i960_kb_sb: + flags = F_I960KB; + break; + case bfd_mach_i960_mc: + flags = F_I960MC; + break; + case bfd_mach_i960_xa: + flags = F_I960XA; + break; + case bfd_mach_i960_ca: + flags = F_I960CA; + break; + case bfd_mach_i960_ka_sa: + flags = F_I960KA; + break; + default: + return false; + } + *flagsp = flags; + return true; + } + break; +#endif +#ifdef MC68MAGIC + case bfd_arch_m68k: + *magicp = MC68MAGIC; + return true; +#endif +#if M88DMAGIC + case bfd_arch_m88k: + *magicp = MC88DMAGIC; + return true; + break; +#endif + + default: /* Unknown architecture */ + return false; + } + + return false; +} + + +static boolean +coff_set_arch_mach(abfd, arch, machine) + bfd *abfd; + enum bfd_architecture arch; + unsigned long machine; +{ + unsigned dummy1, + dummy2; + abfd->obj_arch = arch; + abfd->obj_machine = machine; + if (arch != bfd_arch_unknown && + coff_set_flags(abfd, &dummy1, &dummy2) != true) + return false; /* We can't represent this type */ + return true; /* We're easy ... */ +} + + +/* Calculate the file position for each section. */ + +static void +coff_compute_section_file_positions(abfd) + bfd *abfd; +{ + asection *current; + file_ptr sofar = FILHSZ; + if (bfd_get_start_address(abfd)) { + /* + A start address may have been added to the original file. In this + case it will need an optional header to record it. + */ + abfd->flags |= EXEC_P; + } + if (abfd->flags & EXEC_P) + sofar += AOUTSZ; + + + sofar += abfd->section_count * SCNHSZ; + + for (current = abfd->sections; current != NULL; current = current->next) { + current->filepos = sofar; + /* Only add sections which have contents */ + if (current->flags & SEC_HAS_CONTENTS) + sofar += current->size; + } + obj_relocbase(abfd) = sofar; +} + +/* SUPPRESS 558 */ +/* SUPPRESS 529 */ +static boolean +coff_write_object_contents(abfd) + bfd *abfd; +{ + struct filehdr file_header; + asection *current; + boolean hasrelocs = false; + boolean haslinno = false; + file_ptr reloc_base; + file_ptr lineno_base; + file_ptr sym_base; + file_ptr scn_base; + file_ptr data_base; + unsigned long reloc_size = 0; + unsigned long lnno_size = 0; + asection *text_sec = NULL; + asection *data_sec = NULL; + asection *bss_sec = NULL; + unsigned magic, + flags; + bfd_error = system_call_error; + + + if(abfd->output_has_begun == false) { + coff_compute_section_file_positions(abfd); + } + scn_base = (file_ptr) (sizeof(struct filehdr) + + ((abfd->flags & EXEC_P) ? sizeof(AOUTHDR) : 0)); + + if (bfd_seek(abfd, scn_base, SEEK_SET) != 0) + return false; + reloc_base = obj_relocbase(abfd); + + + /* + Make a pass through the symbol table to count line number entries and + put them into the correct asections + */ + coff_count_linenumbers(abfd); + data_base = scn_base; + /* Work out the size of the reloc and linno areas */ + + for (current = abfd->sections; current != NULL; current = current->next) { + reloc_size += current->reloc_count * sizeof(struct reloc); + lnno_size += current->lineno_count * sizeof(struct lineno); + data_base += sizeof(struct scnhdr); + } + + + lineno_base = reloc_base + reloc_size; + sym_base = lineno_base + lnno_size; + + /* Indicate in each section->line_filepos its actual file address */ + for (current = abfd->sections; current != NULL; current = current->next) { + if (current->lineno_count) { + current->line_filepos = lineno_base; + current->moving_line_filepos = lineno_base; + lineno_base += current->lineno_count * sizeof(struct lineno); + + } + else { + current->line_filepos = 0; + } + if (current->reloc_count) { + current->rel_filepos = reloc_base; + reloc_base += current->reloc_count * sizeof(struct reloc); + } + else { + current->rel_filepos = 0; + } + } + + + + bfd_seek(abfd, + (file_ptr) ((abfd->flags & EXEC_P) ? + (FILHSZ + AOUTSZ) : FILHSZ), + SEEK_SET); + { +#if 0 + unsigned int pad = abfd->flags & D_PAGED ? data_base : 0; +#endif + unsigned int pad = 0; + for (current = abfd->sections; current != NULL; current = current->next) { + SCNHDR section; + strncpy(&(section.s_name[0]), current->name, 8); + section.s_vaddr = current->vma + pad; + section.s_paddr = current->vma + pad; + section.s_size = current->size - pad; + /* + If this section has no size or is unloadable then the scnptr + will be 0 too + */ + if (current->size - pad == 0 || + (current->flags & SEC_LOAD) == 0) { + section.s_scnptr = 0; + + } + else { + section.s_scnptr = current->filepos; + } + section.s_relptr = current->rel_filepos; + section.s_lnnoptr = current->line_filepos; + section.s_nreloc = current->reloc_count; + section.s_nlnno = current->lineno_count; + if (current->reloc_count != 0) + hasrelocs = true; + if (current->lineno_count != 0) + haslinno = true; + + if (!strcmp(current->name, _TEXT)) { + text_sec = current; + section.s_flags = STYP_TEXT; /* kind stupid optimisation */ + } + else { + + if (!strcmp(current->name, _DATA)) { + data_sec = current; + section.s_flags = STYP_DATA; /* kind stupid + optimisation */ + } + else if (!strcmp(current->name, _BSS)) { + bss_sec = current; + section.s_flags = STYP_BSS; /* kind stupid optimisation */ + } + } + + +#ifdef I960 + section.s_align = (current->alignment_power + ? 1 << current->alignment_power + : 0); + +#endif + swap_scnhdr(abfd, §ion); + bfd_write((void *) (§ion), 1, SCNHSZ, abfd); + pad = 0; + } + + } + /* OK, now set up the filehdr... */ + + bfd_h_put_x(abfd, abfd->section_count, &file_header.f_nscns); + /* + We will NOT put a fucking timestamp in the header here. Every time you + put it back, I will come in and take it out again. I'm sorry. This + field does not belong here. We fill it with a 0 so it compares the + same but is not a reasonable time. -- gnu@cygnus.com + */ + /* + Well, I like it, so I'm conditionally compiling it in. + steve@cygnus.com + */ +#ifdef COFF_TIMESTAMP + bfd_h_put_x(abfd, time(0), &file_header.f_timdat); +#else + bfd_h_put_x(abfd, 0, &file_header.f_timdat); +#endif + + if (bfd_get_symcount(abfd) != 0) + bfd_h_put_x(abfd, sym_base, &file_header.f_symptr); + else + bfd_h_put_x(abfd, 0, &file_header.f_symptr); + + file_header.f_flags = 0; + + if (abfd->flags & EXEC_P) + bfd_h_put_x(abfd, sizeof(AOUTHDR), &file_header.f_opthdr); + else + bfd_h_put_x(abfd, 0, &file_header.f_opthdr); + + if (!hasrelocs) + file_header.f_flags |= F_RELFLG; + if (!haslinno) + file_header.f_flags |= F_LNNO; + if (0 == bfd_get_symcount(abfd)) + file_header.f_flags |= F_LSYMS; + if (abfd->flags & EXEC_P) + file_header.f_flags |= F_EXEC; + if (!abfd->xvec->byteorder_big_p) + file_header.f_flags |= F_AR32WR; + /* + FIXME, should do something about the other byte orders and + architectures. + */ + + /* Set up architecture-dependent stuff */ + + magic = 0; + flags = 0; + coff_set_flags(abfd, &magic, &flags); + file_header.f_flags |= flags; + + bfd_h_put_x(abfd, magic, &file_header.f_magic); + bfd_h_put_x(abfd, file_header.f_flags, &file_header.f_flags); + + /* ...and the "opt"hdr... */ +#ifdef I960 + bfd_h_put_x(abfd, (magic == I960ROMAGIC ? NMAGIC : OMAGIC), + &(exec_hdr(abfd)->magic)); +#endif +#if M88 + exec_hdr(abfd)->magic = PAGEMAGIC3; +#endif + + /* Now should write relocs, strings, syms */ + obj_sym_filepos(abfd) = sym_base; + + if (bfd_get_symcount(abfd) != 0) { + coff_mangle_symbols(abfd); + coff_write_symbols(abfd); + coff_write_linenumbers(abfd); + coff_write_relocs(abfd); + } + if (text_sec) { + bfd_h_put_x(abfd, text_sec->size, &exec_hdr(abfd)->tsize); + bfd_h_put_x(abfd, + text_sec->size ? text_sec->vma : 0, + &exec_hdr(abfd)->text_start); + } + if (data_sec) { + bfd_h_put_x(abfd, data_sec->size, &exec_hdr(abfd)->dsize); + bfd_h_put_x(abfd, + data_sec->size ? data_sec->vma : 0, + &exec_hdr(abfd)->data_start); + } + if (bss_sec) { + bfd_h_put_x(abfd, bss_sec->size, &exec_hdr(abfd)->bsize); + } + bfd_h_put_x(abfd, bfd_get_start_address(abfd), &exec_hdr(abfd)->entry); + + + /* now write them */ + bfd_h_put_x(abfd, bfd_get_symcount(abfd), &file_header.f_nsyms); + if (bfd_seek(abfd, 0L, SEEK_SET) != 0) + return false; + + bfd_write((void *) &file_header, 1, FILHSZ, abfd); + + if (abfd->flags & EXEC_P) { + + bfd_write((void *) exec_hdr(abfd), 1, AOUTSZ, abfd); + } + return true; +} + + + +static boolean +coff_set_section_contents(abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + void *location; + file_ptr offset; + size_t count; +{ + if (abfd->output_has_begun == false) /* set by bfd.c handler */ + coff_compute_section_file_positions(abfd); + + bfd_seek(abfd, (file_ptr) (section->filepos + offset), SEEK_SET); + + if (count != 0) { + return (bfd_write(location, 1, count, abfd) == count) ? true : false; + } + return true; +} +static boolean +coff_get_section_contents(abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + void *location; + file_ptr offset; + int count; +{ + if (count == 0 + || offset >= section->size + || bfd_seek(abfd, section->filepos + offset, SEEK_SET) == -1 + || bfd_read(location, 1, count, abfd) != count) { + return (false); + } /* on error */ + return (true); +} /* coff_get_section_contents() */ + + +static boolean +coff_close_and_cleanup(abfd) + bfd *abfd; +{ + if (!bfd_read_p(abfd)) + switch (abfd->format) { + case bfd_archive: + if (!_bfd_write_archive_contents(abfd)) + return false; + break; + case bfd_object: + if (!coff_write_object_contents(abfd)) + return false; + break; + default: + bfd_error = invalid_operation; + return false; + } + +#define cleaner(ptr) if (abfd->ptr) free (abfd->ptr) + cleaner(tdata); + + if (abfd->my_archive) + cleaner(filename); + +#undef cleaner + return true; +} + + + + + + +static void * +buy_and_read(abfd, where, seek_direction, size) + bfd *abfd; + file_ptr where; + int seek_direction; + size_t size; +{ + void *area = (void *) malloc(size); + if (!area) { + bfd_error = no_memory; + return (NULL); + } + bfd_seek(abfd, where, seek_direction); + if (bfd_read(area, 1, size, abfd) != size) { + bfd_error = system_call_error; + free(area); + return (NULL); + } /* on error */ + return (area); +} /* buy_and_read() */ + +static void +offset_symbol_indices(symtab, count, offset) + SYMENT *symtab; + unsigned long count; + long offset; +{ + SYMENT *end = symtab + count; + for (; symtab < end; ++symtab) { + if (symtab->n_sclass == C_FILE) { + symtab->n_value = 0; + } + else if (symtab->n_sclass == C_ALIAS) { + /* + These guys have indices in their values. + */ + symtab->n_value += offset; + + } + else if (symtab->n_numaux) { + /* + anybody else without an aux, has no indices. + */ + + if (symtab->n_sclass == C_EOS + || (BTYPE(symtab->n_type) == T_STRUCT + && symtab->n_sclass != C_STRTAG) + || BTYPE(symtab->n_type) == T_UNION + || BTYPE(symtab->n_type) == T_ENUM) { + + ((AUXENT *) (symtab + 1))->x_sym.x_tagndx += offset; + + } /* These guys have a tagndx */ + if (symtab->n_sclass == C_STRTAG + || symtab->n_sclass == C_UNTAG + || symtab->n_sclass == C_ENTAG + || symtab->n_sclass == C_BLOCK + || symtab->n_sclass == C_FCN + || ISFCN(symtab->n_type)) { + + ((AUXENT *) (symtab + 1))->x_sym.x_fcnary.x_fcn.x_endndx += offset; + + } /* These guys have an endndx */ +#ifndef I960 + if (ISFCN(symtab->n_type)) { + ((AUXENT *) (symtab + 1))->x_sym.x_tvndx += offset; + } /* These guys have a tvndx. I think... + (FIXME) */ +#endif /* Not I960 */ + + } /* if value, else if aux */ + symtab += symtab->n_numaux; + } /* walk the symtab */ + + return; +} /* offset_symbol_indices() */ +/* swap the entire symbol table */ +static void +swap_raw_symtab(abfd, raw_symtab) + bfd *abfd; + SYMENT *raw_symtab; +{ + long i; + SYMENT *end = raw_symtab + bfd_get_symcount(abfd); + for (; raw_symtab < end; ++raw_symtab) { + bfd_coff_swap_sym(abfd, raw_symtab); + + for (i = raw_symtab->n_numaux; i; --i, ++raw_symtab) { + bfd_coff_swap_aux(abfd, + raw_symtab + 1, + raw_symtab->n_type, + raw_symtab->n_sclass); + } /* swap all the aux entries */ + } /* walk the symbol table */ + + return; +} /* swap_raw_symtab() */ +/* + read a symbol table into freshly mallocated memory, swap it, and knit the + symbol names into a normalized form. By normalized here I mean that all + symbols have an n_offset pointer that points to a NULL terminated string. + Oh, and the first symbol MUST be a C_FILE. If there wasn't one there + before, put one there. +*/ + +static SYMENT * +get_normalized_symtab(abfd) + bfd *abfd; +{ + SYMENT *end; + SYMENT *retval; + SYMENT *s; + char *string_table = NULL; + unsigned long size; + unsigned long string_table_size = 0; + /* + I used to SEEK_END here to read the symtab and string table all at + once. This fails if this bfd is really an archive element. Thus, the + somewhat convoluted approach to reading in the string table. xoxorich. + */ + /* + $if ((bfd_seek(abfd, 0, SEEK_END) == -1) || ((end_of_file = + bfd_tell(abfd)) == -1) || (bfd_seek(abfd, obj_sym_filepos(abfd), + SEEK_SET) == -1) || ((beginning_of_symtab = bfd_tell(abfd)) == -1)) { + + bfd_error = system_call_error; return(NULL); }$ + *//* on error */ + + /* $if ((size = end_of_file - beginning_of_symtab) == 0) {$ */ + + if ((size = bfd_get_symcount(abfd) * sizeof(SYMENT)) == 0) { + bfd_error = no_symbols; + return (NULL); + } /* no symbols */ + /* + This is a hack. Some tool chains fail to put a C_FILE symbol at the + beginning of the symbol table. To make life simpler for our users, we + inject one if it wasn't there originally. + + We'd like to keep all of this bfd's native symbols in one block to keep + table traversals simple. To do that, we need to know whether we will + be prepending the C_FILE symbol before we read the rest of the table. + */ + if ((s = (SYMENT *) malloc(sizeof(SYMENT) * 2)) == NULL) { + bfd_error = no_memory; + return (NULL); + } /* on error */ + if (bfd_seek(abfd, obj_sym_filepos(abfd), SEEK_SET) == -1 + || bfd_read(s, sizeof(SYMENT), 1, abfd) != sizeof(SYMENT)) { + bfd_error = system_call_error; + return (NULL); + } /* on error */ + bfd_coff_swap_sym(abfd, s); + + if (s->n_sclass == C_FILE) { + obj_symbol_slew(abfd) = 0; + + if ((retval = (SYMENT *) malloc(size)) == NULL) { + bfd_error = no_memory; + return (NULL); + } /* on malloc error */ + } + else { + unsigned long namelength = 0; + char *filename; + obj_symbol_slew(abfd) = 2; + + if ((retval = (SYMENT *) malloc(size + + (obj_symbol_slew(abfd) + * sizeof(SYMENT)))) == NULL) { + bfd_error = no_memory; + return (NULL); + } /* on malloc error */ + bzero((char *) retval, size + (obj_symbol_slew(abfd) * sizeof(SYMENT))); + +#define FILE_ENTRY_NAME ".file" + + if ((retval->n_offset = (int) malloc(strlen(FILE_ENTRY_NAME) + + 1)) == NULL) { + bfd_error = no_memory; + return (NULL); + } /* on malloc error */ + strcpy((char *) retval->n_offset, FILE_ENTRY_NAME); + retval->n_sclass = C_FILE; + retval->n_scnum = N_DEBUG; + retval->n_numaux = 1; + +#undef FILE_ENTRY_NAME + + if ((filename = bfd_get_filename(abfd)) == NULL) { + filename = "fake"; + } /* if we know it's name */ + if ((namelength = strlen(filename)) <= FILNMLEN) { + strncpy(((AUXENT *) (retval + 1))->x_file.x_fname, filename, FILNMLEN); + } + else { + if ((((AUXENT *) (retval + 1))->x_file.x_n.x_offset + = (int) malloc(namelength)) == NULL) { + bfd_error = no_memory; + return (NULL); + } /* on error */ + strcpy((char *) (((AUXENT *) (retval + 1))->x_file.x_n.x_offset), + filename); + + } /* if "short" name */ + } /* missing file entry. */ + + free(s); + + if (bfd_seek(abfd, obj_sym_filepos(abfd), SEEK_SET) == -1 + || bfd_read(retval + obj_symbol_slew(abfd), size, 1, abfd) != size) { + bfd_error = system_call_error; + return (NULL); + } /* on read error */ + /* mark the end of the symbols */ + end = retval + obj_symbol_slew(abfd) + bfd_get_symcount(abfd); + /* + FIXME SOMEDAY. A string table size of zero is very weird, but + probably possible. If one shows up, it will probably kill us. + */ + + swap_raw_symtab(abfd, retval + obj_symbol_slew(abfd)); + + /* ...and normalize symbol names. */ + + for (s = retval + obj_symbol_slew(abfd); s < end; ++s) { + + if (s->n_zeroes != 0) { + /* + This is a "short" name. Make it long. + */ + unsigned long i = 0; + char *newstring = NULL; + /* + find the length of this string without walking into memory + that isn't ours. + */ + + for (i = 0; i <= 8; ++i) { + if (s->n_name[i] == '\0') { + break; + } /* if end of string */ + } /* possible lengths of this string. */ + + if ((newstring = malloc(++i)) == NULL) { + bfd_error = no_memory; + return (NULL); + } /* on error */ + bzero(newstring, i); + strncpy(newstring, s->n_name, 8); + s->n_offset = (int) newstring; + s->n_zeroes = 0; + + } + else { + if (string_table == NULL) { + /* + NOTE: we don't read the string table until now because we + don't necessarily know that we have one until now. + */ + /* + At this point we should be "seek"'d to the end of the + symbols === the symbol table size. + */ + + if (bfd_read((char *) &string_table_size, sizeof(string_table_size), 1, abfd) != sizeof(string_table_size)) { + bfd_error = system_call_error; + return (NULL); + } /* on error */ + sp(string_table_size); + + if ((string_table = malloc(string_table_size -= 4)) == NULL) { + bfd_error = no_memory; + return (NULL); + } /* on mallocation error */ + if (bfd_read(string_table, string_table_size, 1, abfd) != string_table_size) { + bfd_error = system_call_error; + return (NULL); + } /* on error */ + } /* have not yet read the string table. */ + /* + This is a long name already. Just point it at the string in + memory. + */ + s->n_offset = (int) (string_table - 4 + s->n_offset); + } /* switch on type of symbol name */ + + s += s->n_numaux; + } /* for each symbol */ + /* + If we had to insert a C_FILE symbol, then everybody's indices are off + by 2, so correct them. + */ + + if (obj_symbol_slew(abfd) > 0) { + offset_symbol_indices(retval + 2, bfd_get_symcount(abfd), 2); + + /* and let the world know there are two more of them. */ + bfd_get_symcount(abfd) += 2; + } /* if we added a C_FILE */ + obj_raw_syments(abfd) = retval; + obj_string_table(abfd) = string_table; + + return (retval); +} /* get_normalized_symtab() */ + +static +struct sec_struct * +section_from_bfd_index(abfd, index) + bfd *abfd; + int index; +{ + if (index > 0) { + struct sec_struct *answer = abfd->sections; + while (--index) { + answer = answer->next; + } + return answer; + } + return 0; +} + +static int +coff_get_symcount_upper_bound(ignore_abfd) + bfd *ignore_abfd; +{ + BFD_ASSERT(0); + return 0; +} + +static symindex +coff_get_first_symbol(ignore_abfd) + bfd *ignore_abfd; +{ + return 0; +} + +static symindex +coff_get_next_symbol(abfd, oidx) + bfd *abfd; + symindex oidx; +{ + if (oidx == BFD_NO_MORE_SYMBOLS) + return BFD_NO_MORE_SYMBOLS; + return ++oidx >= bfd_get_symcount(abfd) ? BFD_NO_MORE_SYMBOLS : oidx; +} + +static char * +coff_symbol_name(abfd, idx) + bfd *abfd; + symindex idx; +{ + return (obj_symbols(abfd) + idx)->symbol.name; +} + +static long +coff_symbol_value(abfd, idx) + bfd *abfd; + symindex idx; +{ + return (obj_symbols(abfd) + idx)->symbol.value; +} + +static symclass +coff_classify_symbol(abfd, idx) + bfd *abfd; + symindex idx; +{ + coff_symbol_type *sym = obj_symbols(abfd) + idx; + if ((sym->symbol.flags & BSF_FORT_COMM) != 0) + return bfd_symclass_fcommon; + if ((sym->symbol.flags & BSF_GLOBAL) != 0) + return bfd_symclass_global; + if ((sym->symbol.flags & BSF_DEBUGGING) != 0) + return bfd_symclass_debugger; + if ((sym->symbol.flags & BSF_UNDEFINED) != 0) + return bfd_symclass_undefined; + + return bfd_symclass_unknown; +} + +static boolean +coff_symbol_hasclass(abfd, idx, class) + bfd *abfd; + symindex idx; + symclass class; +{ + + coff_symbol_type *sym = obj_symbols(abfd) + idx; + switch (class) { + case bfd_symclass_fcommon: + return (sym->symbol.flags & BSF_FORT_COMM) ? true : false; + case bfd_symclass_global: + return (sym->symbol.flags & BSF_GLOBAL) ? true : false; + case bfd_symclass_debugger: + return (sym->symbol.flags & BSF_DEBUGGING) ? true : false;; + case bfd_symclass_undefined: + return (sym->symbol.flags & BSF_UNDEFINED) ? true : false;; + default: + return false; + } + +} + + + + +static + boolean +coff_slurp_line_table(abfd, asect) + bfd *abfd; + asection *asect; +{ + struct lineno *native_lineno; + alent *lineno_cache; + BFD_ASSERT(asect->lineno == (alent *) NULL); + + + native_lineno = (struct lineno *) buy_and_read(abfd, + asect->line_filepos, + SEEK_SET, + (size_t) (sizeof(struct lineno) * + asect->lineno_count)); + lineno_cache = + (alent *) malloc((size_t) ((asect->lineno_count + 1) * sizeof(alent))); + if (lineno_cache == NULL) { + bfd_error = no_memory; + return (BFD_FAILURE); + } { /* on error */ + unsigned int counter = 0; + alent *cache_ptr = lineno_cache; + struct lineno *src = native_lineno; + while (counter < asect->lineno_count) { + bfd_coff_swap_lineno(abfd, src); + cache_ptr->line_number = src->l_lnno; + + if (cache_ptr->line_number == 0) { + coff_symbol_type *sym = + (coff_symbol_type *) (src->l_addr.l_symndx + + obj_symbol_slew(abfd) + + obj_raw_syments(abfd))->n_zeroes; + cache_ptr->u.sym = (asymbol *) sym; + sym->lineno = cache_ptr; + } + else { + cache_ptr->u.offset = src->l_addr.l_paddr + - bfd_section_vma(abfd, asect); + } /* If no linenumber expect a symbol index */ + + cache_ptr++; + src++; + counter++; + } + cache_ptr->line_number = 0; + + } + free(native_lineno); + asect->lineno = lineno_cache; + return true; +} /* coff_slurp_line_table() */ + +static SYMENT * +find_next_file_symbol(current, end) + SYMENT *current; + SYMENT *end; +{ + /* ignore the first symbol which is probably a C_FILE. */ + + current += current->n_numaux + 1; + + for (; current < end; ++current) { + if (current->n_sclass == C_FILE) { + return (current); + } /* found one */ + current += current->n_numaux; + } /* walk the remaining table */ + + /* not found */ + return (end); +} /* find_next_file_symbol() */ +/* + Note that C_FILE symbols can, and some do, have more than 1 aux entry. +*/ + +static void +force_indices_file_symbol_relative(abfd, symtab) + bfd *abfd; + SYMENT *symtab; +{ + SYMENT *end = symtab + bfd_get_symcount(abfd); + SYMENT *current; + SYMENT *next; + /* the first symbol had damn well better be a C_FILE. */ + BFD_ASSERT(symtab->n_sclass == C_FILE); + symtab->n_value = 0; + + for (current = find_next_file_symbol(symtab, end); + current < end; + current = next) { + offset_symbol_indices(current, + ((next = + find_next_file_symbol(current, + end)) - current), + symtab - current); + } /* walk the table */ + + return; +} /* force_indices_file_symbol_relative() */ + +static boolean +coff_slurp_symbol_table(abfd) + bfd *abfd; +{ + SYMENT *native_symbols; + coff_symbol_type *cached_area; + unsigned int *table_ptr; + char *string_table = (char *) NULL; + unsigned int number_of_symbols = 0; + if (obj_symbols(abfd)) + return true; + bfd_seek(abfd, obj_sym_filepos(abfd), SEEK_SET); + + /* Read in the symbol table */ + if ((native_symbols = get_normalized_symtab(abfd)) == NULL) { + return (false); + } /* on error */ + force_indices_file_symbol_relative(abfd, native_symbols); + + /* Allocate enough room for all the symbols in cached form */ + cached_area = + (coff_symbol_type *) + malloc((size_t) (bfd_get_symcount(abfd) * sizeof(coff_symbol_type))); + + if (cached_area == NULL) { + bfd_error = no_memory; + return (BFD_FAILURE); + } /* on error */ + table_ptr = + (unsigned int *) + malloc((size_t) (bfd_get_symcount(abfd) * sizeof(unsigned int))); + + if (table_ptr == NULL) { + bfd_error = no_memory; + return (BFD_FAILURE); + } { /* on error */ + coff_symbol_type *dst = cached_area; + unsigned int last_native_index = bfd_get_symcount(abfd); + unsigned int this_index = 0; + while (this_index < last_native_index) { + SYMENT *src = native_symbols + this_index; + table_ptr[this_index] = number_of_symbols; + dst->symbol.the_bfd = abfd; + + dst->symbol.name = (char *) src->n_offset; /* which was normalized + to point to a null + terminated string. */ + /* + We use the native name field to point to the cached field + */ + src->n_zeroes = (int) dst; + dst->symbol.section = section_from_bfd_index(abfd, src->n_scnum); + + switch (src->n_sclass) { +#ifdef I960 + case C_LEAFEXT: +#if 0 + dst->symbol.value = src->n_value - dst->symbol.section->vma; + dst->symbol.flags = BSF_EXPORT | BSF_GLOBAL; + dst->symbol.flags |= BSF_NOT_AT_END; +#endif + /* Fall through to next case */ + +#endif + + case C_EXT: + if (src->n_scnum == 0) { + if (src->n_value == 0) { + dst->symbol.flags = BSF_UNDEFINED; + } + else { + dst->symbol.flags = BSF_FORT_COMM; + dst->symbol.value = src->n_value; + } + } + else { + /* + Base the value as an index from the base of the + section + */ + if (dst->symbol.section == (asection *) NULL) { + dst->symbol.flags = BSF_EXPORT | BSF_GLOBAL | BSF_ABSOLUTE; + dst->symbol.value = src->n_value; + } + else { + dst->symbol.flags = BSF_EXPORT | BSF_GLOBAL; + dst->symbol.value = src->n_value - dst->symbol.section->vma; + } + if (ISFCN(src->n_type)) { + /* + A function ext does not go at the end of a file + */ + dst->symbol.flags |= BSF_NOT_AT_END; + } + } + + break; + case C_STAT: /* static */ +#ifdef I960 + case C_LEAFSTAT: /* static leaf procedure */ +#endif + case C_LABEL: /* label */ + dst->symbol.flags = BSF_LOCAL; + /* + Base the value as an index from the base of the section + */ + dst->symbol.value = src->n_value - dst->symbol.section->vma; + break; + + case C_MOS: /* member of structure */ + case C_EOS: /* end of structure */ + case C_REGPARM: /* register parameter */ + case C_REG: /* register variable */ +#ifdef C_AUTOARG + case C_AUTOARG: /* 960-specific storage class */ +#endif + case C_TPDEF: /* type definition */ + + case C_ARG: + case C_AUTO: /* automatic variable */ + case C_FIELD: /* bit field */ + case C_ENTAG: /* enumeration tag */ + case C_MOE: /* member of enumeration */ + case C_MOU: /* member of union */ + case C_UNTAG: /* union tag */ + + dst->symbol.flags = BSF_DEBUGGING; + dst->symbol.value = src->n_value; + break; + + case C_FILE: /* file name */ + case C_STRTAG: /* structure tag */ + dst->symbol.flags = BSF_DEBUGGING; + dst->symbol.value = src->n_value; + + break; + case C_BLOCK: /* ".bb" or ".eb" */ + case C_FCN: /* ".bf" or ".ef" */ + dst->symbol.flags = BSF_LOCAL; + /* + Base the value as an index from the base of the section + */ + dst->symbol.value = src->n_value - dst->symbol.section->vma; + + break; + case C_EFCN: /* physical end of function */ + case C_NULL: + case C_EXTDEF: /* external definition */ + case C_ULABEL: /* undefined label */ + case C_USTATIC: /* undefined static */ + case C_LINE: /* line # reformatted as symbol table entry */ + case C_ALIAS: /* duplicate tag */ + case C_HIDDEN: /* ext symbol in dmert public lib */ + + default: + + printf("SICK%d\n", src->n_sclass); + abort(); + dst->symbol.flags = BSF_DEBUGGING; + dst->symbol.value = src->n_value; + + break; + } + + + + + BFD_ASSERT(dst->symbol.flags != 0); + + dst->native = src; + + dst->symbol.udata = 0; + dst->lineno = (alent *) NULL; + this_index += src->n_numaux + 1; + dst++; + number_of_symbols++; + } /* walk the native symtab */ + + } /* bfdize the native symtab */ + + obj_symbols(abfd) = cached_area; + obj_raw_syments(abfd) = native_symbols; + + bfd_get_symcount(abfd) = number_of_symbols; + obj_convert(abfd) = table_ptr; + /* Slurp the line tables for each section too */ + { + asection *p; + p = abfd->sections; + while (p) { + coff_slurp_line_table(abfd, p); + p = p->next; + } + } + return true; +} /* coff_slurp_symbol_table() */ + +static unsigned int +coff_get_symtab_upper_bound(abfd) + bfd *abfd; +{ + if (!coff_slurp_symbol_table(abfd)) + return 0; + + return (bfd_get_symcount(abfd) + 1) * (sizeof(coff_symbol_type *)); +} + + +static unsigned int +coff_get_symtab(abfd, alocation) + bfd *abfd; + asymbol **alocation; +{ + unsigned int counter = 0; + coff_symbol_type *symbase; + coff_symbol_type **location = (coff_symbol_type **) (alocation); + if (!coff_slurp_symbol_table(abfd)) + return 0; + + for (symbase = obj_symbols(abfd); counter++ < bfd_get_symcount(abfd);) + *(location++) = symbase++; + *location++ = 0; + return bfd_get_symcount(abfd); +} + +static unsigned int +coff_get_reloc_upper_bound(abfd, asect) + bfd *abfd; + sec_ptr asect; +{ + if (bfd_get_format(abfd) != bfd_object) { + bfd_error = invalid_operation; + return 0; + } + return (asect->reloc_count + 1) * sizeof(arelent *); +} + + +static boolean +coff_slurp_reloc_table(abfd, asect, symbols) + bfd *abfd; + sec_ptr asect; + asymbol **symbols; +{ + struct reloc *native_relocs; + arelent *reloc_cache; + if (asect->relocation) + return true; + if (asect->reloc_count == 0) + return true; + if (!coff_slurp_symbol_table(abfd)) + return false; + native_relocs = + (struct reloc *) buy_and_read(abfd, + asect->rel_filepos, + SEEK_SET, + (size_t) (sizeof(struct reloc) * + asect->reloc_count)); + reloc_cache = (arelent *) + malloc((size_t) (asect->reloc_count * sizeof(arelent))); + + if (reloc_cache == NULL) { + bfd_error = no_memory; + return (BFD_FAILURE); + } { /* on error */ + arelent *cache_ptr; + struct reloc *src; + for (cache_ptr = reloc_cache, + src = native_relocs; + cache_ptr < reloc_cache + asect->reloc_count; + cache_ptr++, + src++) { + asymbol *ptr; + swap_reloc(abfd, src); + src->r_symndx += obj_symbol_slew(abfd); + cache_ptr->sym_ptr_ptr = symbols + obj_convert(abfd)[src->r_symndx]; + + ptr = *(cache_ptr->sym_ptr_ptr); + cache_ptr->address = src->r_vaddr; + /* + The symbols definitions that we have read in have been + relocated as if their sections started at 0. But the offsets + refering to the symbols in the raw data have not been + modified, so we have to have a negative addend to compensate. + */ + + if (ptr->the_bfd == abfd && ptr->section != (asection *) NULL) { + cache_ptr->addend = -ptr->section->vma; + } + else { + cache_ptr->addend = 0; + } + + cache_ptr->address -= asect->vma; + + cache_ptr->section = (asection *) NULL; + +#if I960 + cache_ptr->howto = howto_table + src->r_type; +#endif +#if M88 + if (src->r_type >= R_PCR16L && src->r_type <= R_VRT32) { + cache_ptr->howto = howto_table + src->r_type - R_PCR16L; + } + else { + BFD_ASSERT(0); + } +#endif +#if M68 + cache_ptr->howto = howto_table + src->r_type; +#endif + + } + + } + + free(native_relocs); + asect->relocation = reloc_cache; + return true; +} + + +/* This is stupid. This function should be a boolean predicate */ +static unsigned int +coff_canonicalize_reloc(abfd, section, relptr, symbols) + bfd *abfd; + sec_ptr section; + arelent **relptr; + asymbol **symbols; +{ + arelent *tblptr = section->relocation; + unsigned int count = 0; + if (!(tblptr || coff_slurp_reloc_table(abfd, section, symbols))) + return 0; + tblptr = section->relocation; + if (!tblptr) + return 0; + + for (; count++ < section->reloc_count;) + *relptr++ = tblptr++; + + *relptr = 0; + + return section->reloc_count; +} + + + + + +/* + provided a bfd, a section and an offset into the section, calculate and + return the name of the source file and the line nearest to the wanted + location. +*/ + +static boolean +coff_find_nearest_line(abfd, + section, + symbols, + offset, + filename_ptr, + functionname_ptr, + line_ptr) + bfd *abfd; + asection *section; + asymbol **symbols; + bfd_vma offset; + char **filename_ptr; + char **functionname_ptr; + unsigned int *line_ptr; +{ + static bfd *cache_abfd; + static asection *cache_section; + static bfd_vma cache_offset; + static unsigned int cache_i; + static alent *cache_l; + + unsigned int i = 0; + struct icofdata *cof = obj_icof(abfd); + /* Run through the raw syments if available */ + SYMENT *p = cof->raw_syments; + alent *l; + unsigned int line_base = 0; + *filename_ptr = 0; + *functionname_ptr = 0; + *line_ptr = 0; + /* + I don't know for sure what's right, but this isn't it. First off, an + object file may not have any C_FILE's in it. After + get_normalized_symtab(), it should have at least 1, the one I put + there, but otherwise, all bets are off. Point #2, the first C_FILE + isn't necessarily the right C_FILE because any given object may have + many. I think you'll have to track sections as they coelesce in order + to find the C_STAT symbol for this section. Then you'll have to work + backwards to find the previous C_FILE, or choke if you get to a C_STAT + for the same kind of section. That will mean that the original object + file didn't have a C_FILE. xoxorich. + */ + +#ifdef WEREBEINGPEDANTIC + return false; +#endif + + + + for (i = 0; i < cof->raw_syment_count; i++) { + if (p->n_sclass == C_FILE) { + /* File name is embeded in auxent */ + /* + This isn't right. The fname should probably be normalized + during get_normalized_symtab(). In any case, what was here + wasn't right because a SYMENT.n_name isn't an + AUXENT.x_file.x_fname. xoxorich. + */ + + *filename_ptr = ((AUXENT *) (p + 1))->x_file.x_fname; + break; + } + p += 1 + p->n_numaux; + } + /* Now wander though the raw linenumbers of the section */ + + + + + /* + If this is the same bfd as we were previously called with and this is + the same section, and the offset we want is further down then we can + prime the lookup loop + */ + if (abfd == cache_abfd && + section == cache_section && + offset >= cache_offset) { + i = cache_i; + l = cache_l; + } + else { + i = 0; + l = section->lineno; + } + + for (; i < section->lineno_count; i++) { + if (l->line_number == 0) { + /* Get the symbol this line number points at */ + coff_symbol_type *coff = (coff_symbol_type *) (l->u.sym); + *functionname_ptr = coff->symbol.name; + if (coff->native) { + struct syment *s = coff->native; + s = s + 1 + s->n_numaux; + /* + S should now point to the .bf of the function + */ + if (s->n_numaux) { + /* + The linenumber is stored in the auxent + */ + union auxent *a = (union auxent *) (s + 1); + line_base = a->x_sym.x_misc.x_lnsz.x_lnno; + } + } + } + else { + if (l->u.offset > offset) + break; + *line_ptr = l->line_number + line_base + 1; + } + l++; + } + + cache_abfd = abfd; + cache_section = section; + cache_offset = offset; + cache_i = i; + cache_l = l; + return true; +} diff --git a/bfd/coff-i960.c b/bfd/coff-i960.c new file mode 100644 index 00000000000..3b8e0d60f69 --- /dev/null +++ b/bfd/coff-i960.c @@ -0,0 +1,270 @@ +/* Copyright (C) 1990, 1991 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Diddler. + +BFD 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 1, or (at your option) +any later version. + +BFD 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 BFD; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* $Id$ */ + +#define I960 1 +#include "sysdep.h" +#include "bfd.h" +#include "libbfd.h" +#include "libcoff.h" /* to allow easier abstraction-breaking */ + + + +#include "intel-coff.h" + +#define CALLS 0x66003800 /* Template for 'calls' instruction */ +#define BAL 0x0b000000 /* Template for 'bal' instruction */ +#define BAL_MASK 0x00ffffff + +static bfd_reloc_status_enum_type +optcall_callback(abfd, reloc_entry, symbol_in, data, ignore_input_section) +bfd *abfd; +arelent *reloc_entry; +asymbol *symbol_in; +unsigned char *data; +asection *ignore_input_section; +{ + /* This item has already been relocated correctly, but we may be + * able to patch in yet better code - done by digging out the + * correct info on this symbol */ + bfd_reloc_status_enum_type result; + coff_symbol_type *cs = coffsymbol(symbol_in); + + /* So the target symbol has to be off coff type, and the symbol + has to have the correct native information within it + */ + if ((cs->symbol.the_bfd->xvec->flavour != bfd_target_coff_flavour_enum) + || (cs->native == (struct syment *)NULL)) { + /* This is interesting, consider the case where we're outputting */ + /* coff from a mix n match input, linking from coff to a symbol */ + /* defined in a bout file will cause this match to be true. Should */ + /* I complain ? - This will only work if the bout symbol is non */ + /* leaf. */ + result = bfd_reloc_dangerous; + + } + else { + switch (cs->native->n_sclass) + { + case C_LEAFSTAT: + case C_LEAFEXT: + /* This is a call to a leaf procedure, replace instruction with a bal + to the correct location */ + { + union auxent *aux = (union auxent *)(cs->native+2); + int word = bfd_getlong(abfd, data + reloc_entry->address); + BFD_ASSERT(cs->native->n_numaux==2); + /* We replace the original call instruction with a bal to */ + /* the bal entry point - the offset of which is described in the */ + /* 2nd auxent of the original symbol. We keep the native sym and */ + /* auxents untouched, so the delta between the two is the */ + /* offset of the bal entry point */ + word = ((word + (aux->x_bal.x_balntry - cs->native->n_value)) + & BAL_MASK) | BAL; + bfd_putlong(abfd, word, data+reloc_entry->address); + } + result = bfd_reloc_ok; + break; + case C_SCALL: + { + /* This is a call to a system call, replace with a calls to # */ + BFD_ASSERT(0); + } + break; + default: + result = bfd_reloc_ok; + break; + } + } + return result; +} + + + +static reloc_howto_type howto_table[] = +{ + {0}, + {1}, + {2}, + {3}, + {4}, + {5}, + {6}, + {7}, + {8}, + {9}, + {10}, + {11}, + {12}, + {13}, + {14}, + {15}, + {16}, + + { (unsigned int) R_RELLONG, 0, 2, 32,false, 0, true, true, 0,"rellong", true, 0xffffffff}, + {18}, + {19}, + {20}, + {21}, + {22}, + {23}, + {24}, + + { R_IPRMED, 0, 2, 24,true,0, true, true,0,"iprmed ", true, 0x00ffffff}, + {26}, + + { R_OPTCALL, 0,2,24,true,0, true, true, optcall_callback, "optcall", true, 0x00ffffff}, + +}; + + + +#define BADMAG(x) I960BADMAG(x) +#include "coff-code.h" + + + +bfd_target icoff_big_vec = +{ + "coff-Intel-big", /* name */ + bfd_target_coff_flavour_enum, + false, /* data byte order is little */ + true, /* header byte order is big */ + + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT), + + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* valid reloc types */ + '/', /* ar_pad_char */ + 15, /* ar_max_namelen */ + coff_close_and_cleanup, /* _close_and_cleanup */ + coff_set_section_contents, /* bfd_set_section_contents */ + coff_get_section_contents, /* bfd_get_section_contents */ + coff_new_section_hook, /* new_section_hook */ + _bfd_dummy_core_file_failing_command, /* _core_file_failing_command */ + _bfd_dummy_core_file_failing_signal, /* _core_file_failing_signal */ + _bfd_dummy_core_file_matches_executable_p, /* _core_file_matches_ex...p */ + + bfd_slurp_coff_armap, /* bfd_slurp_armap */ + _bfd_slurp_extended_name_table, /* bfd_slurp_extended_name_table*/ +#if 0 /* */ + bfd_dont_truncate_arname, /* bfd_truncate_arname */ +#else + bfd_bsd_truncate_arname, +#endif + + coff_get_symtab_upper_bound, /* get_symtab_upper_bound */ + coff_get_symtab, /* canonicalize_symtab */ + (void (*)())bfd_false, /* bfd_reclaim_symbol_table */ + coff_get_reloc_upper_bound, /* get_reloc_upper_bound */ + coff_canonicalize_reloc, /* bfd_canonicalize_reloc */ + (void (*)())bfd_false, /* bfd_reclaim_reloc */ + + coff_get_symcount_upper_bound, /* bfd_get_symcount_upper_bound */ + coff_get_first_symbol, /* bfd_get_first_symbol */ + coff_get_next_symbol, /* bfd_get_next_symbol */ + coff_classify_symbol, /* bfd_classify_symbol */ + coff_symbol_hasclass, /* bfd_symbol_hasclass */ + coff_symbol_name, /* bfd_symbol_name */ + coff_symbol_value, /* bfd_symbol_value */ + + _do_getllong, _do_putllong, _do_getlshort, _do_putlshort, /* data */ + _do_getblong, _do_putblong, _do_getbshort, _do_putbshort, /* hdrs */ + + {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ + bfd_generic_archive_p, _bfd_dummy_target}, + {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ + bfd_false}, + coff_make_empty_symbol, + coff_print_symbol, + coff_get_lineno, + coff_set_arch_mach, + coff_write_armap, + bfd_generic_openr_next_archived_file, + coff_find_nearest_line, + bfd_generic_stat_arch_elt /* bfd_stat_arch_elt */ + }; + + + +bfd_target icoff_little_vec = +{ + "coff-Intel-little", /* name */ + bfd_target_coff_flavour_enum, + false, /* data byte order is little */ + false, /* header byte order is little */ + + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT), + + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* valid reloc types */ + '/', /* ar_pad_char */ + 15, /* ar_max_namelen */ + coff_close_and_cleanup, /* _close_and_cleanup */ + coff_set_section_contents, /* bfd_set_section_contents */ + coff_get_section_contents, /* bfd_get_section_contents */ + coff_new_section_hook, /* new_section_hook */ + _bfd_dummy_core_file_failing_command, /* _core_file_failing_command */ + _bfd_dummy_core_file_failing_signal, /* _core_file_failing_signal */ + _bfd_dummy_core_file_matches_executable_p, /* _core_file_matches_ex...p */ + + bfd_slurp_coff_armap, /* bfd_slurp_armap */ + _bfd_slurp_extended_name_table, /* bfd_slurp_extended_name_table*/ +#if 0 /* */ + bfd_dont_truncate_arname, /* bfd_truncate_arname */ +#else + bfd_bsd_truncate_arname, +#endif + coff_get_symtab_upper_bound, /* get_symtab_upper_bound */ + coff_get_symtab, /* canonicalize_symtab */ + (void (*)())bfd_false, /* bfd_reclaim_symbol_table */ + coff_get_reloc_upper_bound, /* get_reloc_upper_bound */ + coff_canonicalize_reloc, /* bfd_canonicalize_reloc */ + (void (*)())bfd_false, /* bfd_reclaim_reloc */ + + coff_get_symcount_upper_bound, /* bfd_get_symcount_upper_bound */ + coff_get_first_symbol, /* bfd_get_first_symbol */ + coff_get_next_symbol, /* bfd_get_next_symbol */ + coff_classify_symbol, /* bfd_classify_symbol */ + coff_symbol_hasclass, /* bfd_symbol_hasclass */ + coff_symbol_name, /* bfd_symbol_name */ + coff_symbol_value, /* bfd_symbol_value */ + + _do_getllong, _do_putllong, _do_getlshort, _do_putlshort, /* data */ + _do_getllong, _do_putllong, _do_getlshort, _do_putlshort, /* hdrs */ + + {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ + bfd_generic_archive_p, _bfd_dummy_target}, + {bfd_false, coff_mkobject, /* bfd_set_format */ + _bfd_generic_mkarchive, bfd_false}, + coff_make_empty_symbol, + coff_print_symbol, + coff_get_lineno, + coff_set_arch_mach, + coff_write_armap, + bfd_generic_openr_next_archived_file, + coff_find_nearest_line, + bfd_generic_stat_arch_elt /* bfd_stat_arch_elt */ +}; + + diff --git a/bfd/libaout.h b/bfd/libaout.h new file mode 100644 index 00000000000..febe2f47885 --- /dev/null +++ b/bfd/libaout.h @@ -0,0 +1,80 @@ +/* Copyright (C) 1990, 1991 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Diddler. + +BFD 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 1, or (at your option) +any later version. + +BFD 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 BFD; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* $Id$ */ + +/* BFD back-end data structures for a.out (and similar) files. + + We try to encapsulate the differences in a few routines, and otherwise + share large masses of code. This means we only have to fix bugs in + one place, most of the time. */ + +/** a.out files */ + +#define exec_hdr(bfd) (((struct sunexdata *) ((bfd)->tdata))->hdr) +/*#define obj_symbols(bfd) ((((struct sunexdata *) ((bfd)->tdata))->symbols))*/ +#define obj_textsec(bfd) (((struct sunexdata *) ((bfd)->tdata))->textsec) +#define obj_datasec(bfd) (((struct sunexdata *) ((bfd)->tdata))->datasec) +#define obj_bsssec(bfd) (((struct sunexdata *) ((bfd)->tdata))->bsssec) +#define obj_sym_filepos(bfd) (((struct sunexdata *) ((bfd)->tdata))->sym_filepos) +#define obj_str_filepos(bfd) (((struct sunexdata *) ((bfd)->tdata))->str_filepos) + + + +typedef struct { + asymbol symbol; + short desc; +char other; +unsigned char type; +} aout_symbol_type; + + +struct sunexdata { + struct exec *hdr; /* exec file header */ + aout_symbol_type *symbols; /* symtab for input bfd */ + + + /* For ease, we do this */ + asection *textsec; + asection *datasec; + asection *bsssec; + + /* We remember these offsets so that after check_file_format, we have + no dependencies on the particular format of the exec_hdr. */ + file_ptr sym_filepos; + file_ptr str_filepos; +}; + + +#define obj_outsymbols(bfd) ((void *)(((struct sunexdata *) ((bfd)->tdata))->outsymbols)) + + + +/* We case the address of the first element of a asymbol to ensure that the + * macro is only every applied to an asymbol + */ +#define aout_symbol(asymbol) ((aout_symbol_type *)(&(asymbol)->the_bfd)) + +/*#define obj_symbols(bfd) ((((struct sunexdata *) ((bfd)->tdata))->symbols))*/ +#define obj_aout_symbols(bfd) ((((struct sunexdata *) (bfd)->tdata))->symbols) +#define obj_arch_flags(bfd) ((((struct sunexdata *) (bfd)->tdata))->arch_flags) + +#define get_tdata(x) ((struct sunexdata *)((x)->tdata)) +#define set_tdata(x,y) ((x)->tdata = (void *) (y)) + + diff --git a/bfd/libbfd.c b/bfd/libbfd.c new file mode 100644 index 00000000000..9998690f042 --- /dev/null +++ b/bfd/libbfd.c @@ -0,0 +1,332 @@ +/* Copyright (C) 1990, 1991 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Diddler. + +BFD 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 1, or (at your option) +any later version. + +BFD 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 BFD; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* $Id$ */ + +/*** libbfd.c -- random bfd support routines used internally only. */ +#include "sysdep.h" +#include "bfd.h" +#include "libbfd.h" + + + +/** Dummies for targets that don't want or need to implement + certain operations */ + +boolean +_bfd_dummy_new_section_hook (ignore, ignore_newsect) + bfd *ignore; + asection *ignore_newsect; +{ + return true; +} + +boolean +bfd_false (ignore) + bfd *ignore; +{ + return false; +} + +boolean +bfd_true (ignore) + bfd *ignore; +{ + return true; +} + +void * +bfd_nullvoidptr(ignore) +bfd *ignore; +{ + return (void *)NULL; +} +int +bfd_0(ignore) +bfd *ignore; +{ + return 0; +} +unsigned int +bfd_0u(ignore) +bfd *ignore; +{ + return 0; +} + +void +bfd_void(ignore) +bfd *ignore; +{ +} + +boolean +_bfd_dummy_core_file_matches_executable_p (ignore_core_bfd, ignore_exec_bfd) + bfd *ignore_core_bfd; +bfd *ignore_exec_bfd; +{ + bfd_error = invalid_operation; + return false; +} + +/* of course you can't initialize a function to be the same as another, grr */ + +char * +_bfd_dummy_core_file_failing_command (ignore_abfd) + bfd *ignore_abfd; +{ + return (char *)NULL; +} + +int +_bfd_dummy_core_file_failing_signal (ignore_abfd) + bfd *ignore_abfd; +{ + return 0; +} + +bfd_target * +_bfd_dummy_target (ignore_abfd) + bfd *ignore_abfd; +{ + return 0; +} + +/** zalloc -- allocate and clear storage */ + + +#ifndef zalloc +char * +zalloc (size) + size_t size; +{ + char *ptr = malloc (size); + + if ((ptr != NULL) && (size != 0)) + bzero (ptr, size); + + return ptr; +} +#endif + +/* Some IO code */ + + +/* Note that archive entries don't have streams; they share their parent's. + This allows someone to play with the iostream behind bfd's back. + + Also, note that the origin pointer points to the beginning of a file's + contents (0 for non-archive elements). For archive entries this is the + first octet in the file, NOT the beginning of the archive header. */ + +size_t +bfd_read (ptr, size, nitems, abfd) + void *ptr; + size_t size; + size_t nitems; + bfd *abfd; +{ + return fread (ptr, 1, size*nitems, bfd_cache_lookup(abfd)); +} + +size_t +bfd_write (ptr, size, nitems, abfd) + void *ptr; + size_t size; + size_t nitems; + bfd *abfd; +{ + return fwrite (ptr, 1, size*nitems, bfd_cache_lookup(abfd)); +} + +int +bfd_seek (abfd, position, direction) +bfd *abfd; +file_ptr position; +int direction; +{ + /* For the time being, a bfd may not seek to it's end. The + problem is that we don't easily have a way to recognize + the end of an element in an archive. */ + + BFD_ASSERT(direction == SEEK_SET + || direction == SEEK_CUR); + + if (direction == SEEK_SET && abfd->my_archive != NULL) + { + /* This is a set within an archive, so we need to + add the base of the object within the archive */ + return(fseek(bfd_cache_lookup(abfd), + position + abfd->origin, + direction)); + } + else + { + return(fseek(bfd_cache_lookup(abfd), position, direction)); + } +} + +long +bfd_tell (abfd) + bfd *abfd; +{ + file_ptr ptr; + + ptr = ftell (bfd_cache_lookup(abfd)); + + if (abfd->my_archive) + ptr -= abfd->origin; + return ptr; +} + +/** Make a string table */ + +/* Add string to table pointed to by table, at location starting with free_ptr. + resizes the table if necessary (if it's NULL, creates it, ignoring + table_length). Updates free_ptr, table, table_length */ + +boolean +bfd_add_to_string_table (table, new_string, table_length, free_ptr) + char **table, **free_ptr; + char *new_string; + unsigned int *table_length; +{ + size_t string_length = strlen (new_string) + 1; /* include null here */ + char *base = *table; + size_t space_length = *table_length; + unsigned int offset = (base ? *free_ptr - base : 0); + + if (base == NULL) { + /* Avoid a useless regrow if we can (but of course we still + take it next time */ + space_length = (string_length < DEFAULT_STRING_SPACE_SIZE ? + DEFAULT_STRING_SPACE_SIZE : string_length+1); + base = zalloc (space_length); + + if (base == NULL) { + bfd_error = no_memory; + return false; + } + } + + if ((size_t)(offset + string_length) >= space_length) { + /* Make sure we will have enough space */ + while ((size_t)(offset + string_length) >= space_length) + space_length += space_length/2; /* grow by 50% */ + + base = (char *) realloc (base, space_length); + if (base == NULL) { + bfd_error = no_memory; + return false; + } + + } + + memcpy (base + offset, new_string, string_length); + *table = base; + *table_length = space_length; + *free_ptr = base + offset + string_length; + + return true; +} + +/** The do-it-yourself (byte) sex-change kit */ + +/* The middle letter e.g. getshort indicates Big or Little endian + target machine. It doesn't matter what the byte order of the host + machine is; these routines work for either. */ + +/* FIXME: Should these take a count argument? + Answer (gnu@cygnus.com): No, but perhaps they should be inline + functions in swap.h #ifdef __GNUC__. + Gprof them later and find out. */ + +short +_do_getbshort (addr) + register bfd_byte *addr; +{ + return (addr[0] << 8) | addr[1]; +} + +short +_do_getlshort (addr) + register bfd_byte *addr; +{ + return (addr[1] << 8) | addr[0]; +} + +void +_do_putbshort (data, addr) + int data; /* Actually short, but ansi C sucks */ + register bfd_byte *addr; +{ + addr[0] = (bfd_byte)(data >> 8); + addr[1] = (bfd_byte )data; +} + +void +_do_putlshort (data, addr) + int data; /* Actually short, but ansi C sucks */ + register bfd_byte *addr; +{ + addr[0] = (bfd_byte )data; + addr[1] = (bfd_byte)(data >> 8); +} + +long +_do_getblong (addr) + register bfd_byte *addr; +{ + return ((((addr[0] << 8) | addr[1]) << 8) | addr[2]) << 8 | addr[3]; +} + +long +_do_getllong (addr) + register bfd_byte *addr; +{ + return ((((addr[3] << 8) | addr[2]) << 8) | addr[1]) << 8 | addr[0]; +} + +void +_do_putblong (data, addr) + unsigned long data; + register bfd_byte *addr; +{ + addr[0] = (bfd_byte)(data >> 24); + addr[1] = (bfd_byte)(data >> 16); + addr[2] = (bfd_byte)(data >> 8); + addr[3] = (bfd_byte)data; +} + +void +_do_putllong (data, addr) + unsigned long data; + register bfd_byte *addr; +{ + addr[0] = (bfd_byte)data; + addr[1] = (bfd_byte)(data >> 8); + addr[2] = (bfd_byte)(data >> 16); + addr[3] = (bfd_byte)(data >> 24); +} + + + + + + + diff --git a/bfd/libbfd.h b/bfd/libbfd.h new file mode 100644 index 00000000000..790d957c300 --- /dev/null +++ b/bfd/libbfd.h @@ -0,0 +1,160 @@ +/* Copyright (C) 1990, 1991 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Diddler. + +BFD 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 1, or (at your option) +any later version. + +BFD 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 BFD; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* $Id$ */ + +/*** libbfd.h -- Declarations used by bfd library implementation. + This include file is not for users of the library */ + + + + + +/* If you want to read and write large blocks, you might want to do it + in quanta of this amount */ +#define DEFAULT_BUFFERSIZE 8192 + +/* tdata for an archive. For an input archive cache + needs to be free()'d. For an output archive, symdefs do. +*/ + +struct artdata { + file_ptr first_file_filepos; + /* Speed up searching the armap */ + struct ar_cache *cache; + bfd *archive_head; /* Only interesting in output routines */ + carsym *symdefs; /* the symdef entries */ + symindex symdef_count; /* how many there are */ + char *extended_names; /* clever intel extension */ +}; + +#define bfd_ardata(bfd) ((struct artdata *) ((bfd)->tdata)) +#define bfd_set_ardata(bfd, v) ((bfd)->tdata = (void *) (v)) + +/* Goes in bfd's arelt_data slot */ +struct areltdata { + char * arch_header; /* it's actually a string */ + unsigned int parsed_size; /* octets of filesize not including ar_hdr */ + char *filename; /* null-terminated */ +}; + +#define arelt_size(bfd) (((struct areltdata *)((bfd)->arelt_data))->parsed_size) + +/* FIXME -- a lot of my code allocates a large block and subdivides it. + This can't always work, because of alignment restrictions. We should change + it before it becomes a problem -- Gumby */ + +PROTO (char *, zalloc, (size_t size)); +PROTO (char *, realloc, (char * ptr, size_t size)); +PROTO (bfd_target *, bfd_find_target, (char *target_name)); +PROTO (size_t, bfd_read, (void *ptr, size_t size, size_t nitems, bfd *abfd)); +PROTO (size_t, bfd_write, (void *ptr, size_t size, size_t nitems, bfd *abfd)); + + + +PROTO (FILE *, bfd_cache_lookup, (bfd *)); +PROTO (void, bfd_cache_close, (bfd *)); +PROTO (int, bfd_seek,(bfd*, file_ptr, int direction)); +PROTO (long, bfd_tell, (bfd *abfd)); +PROTO (bfd *, _bfd_create_empty_archive_element_shell, (bfd *obfd)); +PROTO (bfd *, look_for_bfd_in_cache, (bfd *arch_bfd, file_ptr index)); +PROTO (boolean, _bfd_generic_mkarchive, (bfd *abfd)); +PROTO (struct areltdata *, snarf_ar_hdr, (bfd *abfd)); +PROTO (bfd_target *, bfd_generic_archive_p, (bfd *abfd)); +PROTO (boolean, bfd_slurp_bsd_armap, (bfd *abfd)); +PROTO (boolean, bfd_slurp_coff_armap, (bfd *abfd)); +PROTO (boolean, _bfd_slurp_extended_name_table, (bfd *abfd)); +PROTO (boolean, _bfd_write_archive_contents, (bfd *abfd)); +PROTO (bfd *, new_bfd, ()); + +#define DEFAULT_STRING_SPACE_SIZE 0x2000 +PROTO (boolean, bfd_add_to_string_table, (char **table, char *new_string, + unsigned int *table_length, + char **free_ptr)); + +PROTO (long, _do_getblong, (unsigned char *addr)); +PROTO (long, _do_getllong, (unsigned char *addr)); +PROTO (short, _do_getbshort, (unsigned char *addr)); +PROTO (short, _do_getlshort, (unsigned char *addr)); +PROTO (void, _do_putblong, (unsigned long data, unsigned char *addr)); +PROTO (void, _do_putllong, (unsigned long data, unsigned char *addr)); +PROTO (void, _do_putbshort, (int data, unsigned char *addr)); +PROTO (void, _do_putlshort, (int data, unsigned char *addr)); + +PROTO (boolean, bfd_false, (bfd *ignore)); +PROTO (boolean, bfd_true, (bfd *ignore)); +PROTO (void *, bfd_nullvoidptr, (bfd *ignore)); +PROTO (int, bfd_0, (bfd *ignore)); +PROTO (unsigned int, bfd_0u, (bfd *ignore)); +PROTO (void, bfd_void, (bfd *ignore)); + + +PROTO (bfd *,new_bfd_contained_in,(bfd *)); +PROTO (boolean, _bfd_dummy_new_section_hook, (bfd *ignore, asection *newsect)); +PROTO (char *, _bfd_dummy_core_file_failing_command, (bfd *abfd)); +PROTO (int, _bfd_dummy_core_file_failing_signal, (bfd *abfd)); +PROTO (boolean, _bfd_dummy_core_file_matches_executable_p, (bfd *core_bfd, + bfd *exec_bfd)); +PROTO (bfd_target *, _bfd_dummy_target, (bfd *abfd)); + +PROTO (void, bfd_dont_truncate_arname, (bfd *abfd, char *filename, char *hdr)); +PROTO (void, bfd_bsd_truncate_arname, (bfd *abfd, char *filename, char *hdr)); +PROTO (void, bfd_gnu_truncate_arname, (bfd *abfd, char *filename, char *hdr)); + +PROTO (boolean, bsd_write_armap, (bfd *arch, unsigned int elength, + struct orl *map, int orl_count, int stridx)); + +PROTO (boolean, coff_write_armap, (bfd *arch, unsigned int elength, + struct orl *map, int orl_count, int stridx)); + +PROTO ( bfd *,bfd_generic_openr_next_archived_file, (bfd *archive, bfd *last_file)); + +PROTO(int, bfd_generic_stat_arch_elt, (bfd *, struct stat *)); +/* Macros to tell if bfds are read or write enabled. + + Note that bfds open for read may be scribbled into if the fd passed + to bfd_fdopenr is actually open both for read and write + simultaneously. However an output bfd will never be open for + read. Therefore sometimes you want to check bfd_read_p or + !bfd_read_p, and only sometimes bfd_write_p. +*/ + +#define bfd_read_p(abfd) ((abfd)->direction == read_direction || (abfd)->direction == both_direction) +#define bfd_write_p(abfd) ((abfd)->direction == write_direction || (abfd)->direction == both_direction) + +PROTO (void, bfd_assert,(char*,int)); +#define BFD_ASSERT(x) \ +{ if (!(x)) bfd_assert(__FILE__,__LINE__); } + +#define BFD_FAIL() \ +{ bfd_assert(__FILE__,__LINE__); } + +PROTO (FILE *, bfd_cache_lookup_worker, (bfd *)); + +extern bfd *bfd_last_cache; +#define bfd_cache_lookup(x) \ + (x==bfd_last_cache?(FILE*)(bfd_last_cache->iostream):bfd_cache_lookup_worker(x)) + +/* Now Steve, what's the story here? */ +#ifdef lint +#define itos(x) "l" +#define stoi(x) 1 +#else +#define itos(x) ((char*)(x)) +#define stoi(x) ((int)(x)) +#endif diff --git a/bfd/libcoff.h b/bfd/libcoff.h new file mode 100644 index 00000000000..46f5a783650 --- /dev/null +++ b/bfd/libcoff.h @@ -0,0 +1,62 @@ +/* Copyright (C) 1990, 1991 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Diddler. + +BFD 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 1, or (at your option) +any later version. + +BFD 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 BFD; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* $Id$ */ + +/* BFD COFF object file private structure. */ + +/* Object file tdata; access macros */ + +#define obj_icof(bfd) ((struct icofdata *) ((bfd)->tdata)) +#define exec_hdr(bfd) (obj_icof(bfd)->hdr) +#define obj_symbols(bfd) (obj_icof(bfd)->symbols) +#define obj_sym_filepos(bfd) (obj_icof(bfd)->sym_filepos) + +#define obj_relocbase(bfd) (obj_icof(bfd)->relocbase) +#define obj_raw_syments(bfd) (obj_icof(bfd)->raw_syments) +#define obj_convert(bfd) (obj_icof(bfd)->conversion_table) +#define obj_symbol_slew(bfd) (obj_icof(bfd)->symbol_index_slew) +#define obj_string_table(bfd) (obj_icof(bfd)->string_table) + +typedef struct { + asymbol symbol; + struct syment *native; + struct lineno_cache_entry *lineno; +} coff_symbol_type; + +struct icofdata { + struct aouthdr *hdr; /* exec file header */ + coff_symbol_type *symbols; /* symtab for input bfd */ + unsigned int *conversion_table; + file_ptr sym_filepos; + + long symbol_index_slew; /* used during read to mark whether a + C_FILE symbol as been added. */ + + struct syment *raw_syments; + struct lineno *raw_linenos; + unsigned int raw_syment_count; + char *string_table; + /* These are only valid once writing has begun */ + long int relocbase; + +}; + +/* We cast the address of the first element of a asymbol to ensure that the + * macro is only ever applied to an asymbol. */ +#define coffsymbol(asymbol) ((coff_symbol_type *)(&((asymbol)->the_bfd))) diff --git a/bfd/misc.c b/bfd/misc.c new file mode 100755 index 00000000000..041fcde8623 --- /dev/null +++ b/bfd/misc.c @@ -0,0 +1,98 @@ +/* Copyright (C) 1990, 1991 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Diddler. + +BFD 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 1, or (at your option) +any later version. + +BFD 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 BFD; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* $Id$ */ + +#if 0 + /* xoxorich. coelesced from other binutils. */ +/* This crap should all be bundled with the binutils, or else be in its + own library, but for expediency we are doing it this way right now. */ + +/* + * Last Mod Mon Feb 18 14:49:39 PST 1991, by rich@cygint.cygnus.com + */ + +#include +#include "misc.h" +#if __STDC__ +extern char *realloc (char * ptr, int size); +extern char *malloc (int size); +#else +extern char *realloc (); +extern char *malloc (); +#endif + +/* Print the filename of the current file on 'outfile' (a stdio stream). */ + +/* Current file's name */ + +char *input_name; + +/* Current member's name, or 0 if processing a non-library file. */ + +char *input_member; + +void print_file_name (outfile) + FILE *outfile; +{ + fprintf (outfile, "%s", input_name); + if (input_member) + fprintf (outfile, "(%s)", input_member); +} + +/* process one input file */ +void scan_library (); + +char *program_name; + +/* Report a nonfatal error. + STRING is a format for printf, and ARG1 ... ARG3 are args for it. */ +/*VARARGS*/ +void +error (string, arg1, arg2, arg3) + char *string, *arg1, *arg2, *arg3; +{ + fprintf (stderr, "%s: ", program_name); + fprintf (stderr, string, arg1, arg2, arg3); + fprintf (stderr, "\n"); +} + + + +/* Report a nonfatal error. + STRING is printed, followed by the current file name. */ + +void +error_with_file (string) + char *string; +{ + fprintf (stderr, "%s: ", program_name); + print_file_name (stderr); + fprintf (stderr, ": "); + fprintf (stderr, string); + fprintf (stderr, "\n"); +} + +/* Like malloc but get fatal error if memory is exhausted. */ + + +/* Like realloc but get fatal error if memory is exhausted. */ + + +/* end of misc.c */ +#endif diff --git a/bfd/misc.h b/bfd/misc.h new file mode 100755 index 00000000000..05935c28f6f --- /dev/null +++ b/bfd/misc.h @@ -0,0 +1,93 @@ +/* Copyright (C) 1990, 1991 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Diddler. + +BFD 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 1, or (at your option) +any later version. + +BFD 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 BFD; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* $Id$ */ + +/* xoxorich. coelesced from binutils. + * + * Last Mod Mon Feb 18 14:49:51 PST 1991, by rich@cygint.cygnus.com + */ + +#ifndef MISC_H +#define MISC_H 1 + +#include "ranlib.h" + +#ifdef USG +#include +#else +#include +#endif /* USG */ + +#ifdef never +#ifdef LOCKS +#undef LOCKS +#endif /* LOCKS */ +#endif /* never */ + + /* used for masking system io calls into stdio. */ + +/* the name, ie, argv[0], of this program. */ + +extern char *program_name; + +/* Current file's name */ + +extern char *input_name; + +/* Current member's name, or 0 if processing a non-library file. */ + +extern char *input_member; + +/* Report an error using the message for the last failed system call, + followed by the string NAME. */ + +#define perror_name(name) perror(concat(program_name, ": error on ", name)) +#define pfatal_with_name(name) {perror_name(name);exit(-1);} + +#ifdef __STDC__ + +extern char *concat(char *a, char *b, char *c); +extern void *xmalloc(unsigned int size); +extern void * xrealloc(char *ptr, int size); +extern void error(char *string, char *arg1, char *arg2, char *arg3); +extern void error_with_file(char *string); +extern void fatal(char *string, char*a1, char*a2, char*a3); +extern void print_file_name(FILE *outfile); +extern void swap_symdef_table(struct symdef *sym, int count); +#else +extern char *alloca(); +extern char *concat(); +extern void * xmalloc(); +extern void *xrealloc(); +extern void error(); +extern void error_with_file(); +extern void fatal(); +extern void print_file_name(); +extern void swap_symdef_table(); +#endif /* __STDC__ */ + +#endif /* MISC_H */ + +/* + * Local Variables: + * comment-column: 0 + * End: + */ + +/* end of misc.h */ diff --git a/bfd/opncls.c b/bfd/opncls.c new file mode 100644 index 00000000000..63e9c51daed --- /dev/null +++ b/bfd/opncls.c @@ -0,0 +1,281 @@ +/* Copyright (C) 1990, 1991 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Diddler. + +BFD 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 1, or (at your option) +any later version. + +BFD 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 BFD; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* $Id$ */ + +/*** opncls.c -- open and close a bfd. */ + +#include "sysdep.h" +#include "bfd.h" +#include "libbfd.h" + + +extern void bfd_cache_init(); +FILE *bfd_open_file(); + +/* fdopen is a loser -- we should use stdio exclusively. Unfortunately + if we do that we can't use fcntl. */ + +/** Locking + + Locking is loosely controlled by the preprocessor variable + BFD_LOCKS. I say loosely because Unix barely understands locking + -- at least in BSD it doesn't affect programs which don't + explicitly use it! That is to say it's practically useless, though + if everyone uses this library you'll be OK. + + From among the many and varied lock facilities available, (none of + which, of course, knows about any other) we use the fcntl locks, + because they're Posix. + + The reason that bfd_openr and bfd_fdopenr exist, yet only bfd_openw + exists is because of locking. When we do output, we lock the + filename file for output, then open a temporary file which does not + actually get its correct filename until closing time. This is + safest, but requires the asymmetry in read and write entry points. + + Perhaps, since unix has so many different kinds of locking anyway, + we should use the emacs lock scheme?... */ + + +bfd *new_bfd() +{ + bfd *nbfd = (bfd *)zalloc(sizeof(bfd)); + + nbfd->direction = no_direction; + nbfd->iostream = NULL; + nbfd->where = 0; + nbfd->sections = (asection *)NULL; + nbfd->format = bfd_unknown; + nbfd->my_archive = (bfd *)NULL; + nbfd->origin = 0; + nbfd->opened_once = false; + nbfd->output_has_begun = false; + nbfd->section_count = 0; + nbfd->usrdata = (void *)NULL; + nbfd->sections = (asection *)NULL; + nbfd->cacheable = false; + nbfd->flags = NO_FLAGS; + return nbfd; +} +bfd *new_bfd_contained_in(obfd) +bfd *obfd; +{ + bfd *nbfd = new_bfd(obfd); + nbfd->xvec = obfd->xvec; + nbfd->my_archive = obfd; + nbfd->direction = read_direction; + return nbfd; +} + +/** bfd_openr, bfd_fdopenr -- open for reading. + Returns a pointer to a freshly-allocated bfd on success, or NULL. */ + +bfd * +bfd_openr (filename, target) + char *filename; + char *target; +{ + bfd *nbfd; + bfd_target *target_vec; + + target_vec = bfd_find_target (target); + if (target_vec == NULL) { + bfd_error = invalid_target; + return NULL; + } + + bfd_error = system_call_error; + nbfd = new_bfd(); + if (nbfd == NULL) { + bfd_error = no_memory; + return NULL; + } + + nbfd->filename = filename; + nbfd->xvec = target_vec; + nbfd->direction = read_direction; + + if (bfd_open_file (nbfd) == NULL) { + bfd_error = system_call_error; /* File didn't exist, or some such */ + free (nbfd); + return NULL; + } + return nbfd; +} + + +/* Don't try to `optimize' this function: + + o - We lock using stack space so that interrupting the locking + won't cause a storage leak. + o - We open the file stream last, since we don't want to have to + close it if anything goes wrong. Closing the stream means closing + the file descriptor too, even though we didn't open it. + */ + +bfd * +bfd_fdopenr (filename, target, fd) + char *filename; + char *target; + int fd; +{ + bfd *nbfd; + bfd_target *target_vec; + int fdflags; +#ifdef BFD_LOCKS + struct flock lock, *lockp = &lock; +#endif + + target_vec = bfd_find_target (target); + if (target_vec == NULL) { + bfd_error = invalid_target; + return NULL; + } + + bfd_error = system_call_error; + + fdflags = fcntl (fd, F_GETFL); + if (fdflags == -1) return NULL; + +#ifdef BFD_LOCKS + lockp->l_type = F_RDLCK; + if (fcntl (fd, F_SETLKW, lockp) == -1) return NULL; +#endif + + nbfd = new_bfd(); + + if (nbfd == NULL) { + bfd_error = no_memory; + return NULL; + } +#ifdef BFD_LOCKS + nbfd->lock = (struct flock *) (nbfd + 1); +#endif + /* if the fd were open for read only, this still would not hurt: */ + nbfd->iostream = (char *) fdopen (fd, "r+"); + if (nbfd->iostream == NULL) { + free (nbfd); + return NULL; + } + + /* OK, put everything where it belongs */ + + nbfd->filename = filename; + nbfd->xvec = target_vec; + + /* As a special case we allow a FD open for read/write to + be written through, although doing so requires that we end + the previous clause with a preposition. */ + switch (fdflags & O_ACCMODE) { + case O_RDONLY: nbfd->direction = read_direction; break; + case O_WRONLY: nbfd->direction = write_direction; break; + case O_RDWR: nbfd->direction = both_direction; break; + default: abort (); + } + +#ifdef BFD_LOCKS + memcpy (nbfd->lock, lockp, sizeof (struct flock)) +#endif + + bfd_cache_init (nbfd); + + return nbfd; +} + +/** bfd_openw -- open for writing. + Returns a pointer to a freshly-allocated bfd on success, or NULL. + + See comment by bfd_fdopenr before you try to modify this function. */ + +bfd * +bfd_openw (filename, target) + char *filename; + char *target; +{ + bfd *nbfd; + bfd_target *target_vec; + + target_vec = bfd_find_target (target); + if (target_vec == NULL) return NULL; + + bfd_error = system_call_error; + + /* nbfd has to point to head of malloc'ed block so that bfd_close may + reclaim it correctly. */ + + nbfd = new_bfd(); + if (nbfd == NULL) { + bfd_error = no_memory; + return NULL; + } + + nbfd->filename = filename; + nbfd->xvec = target_vec; + nbfd->direction = write_direction; + + if (bfd_open_file (nbfd) == NULL) { + bfd_error = system_call_error; /* File not writeable, etc */ + free (nbfd); + return NULL; + } + return nbfd; +} + + + +/** Close up shop, get your deposit back. */ +boolean +bfd_close (abfd) + bfd *abfd; +{ + if (BFD_SEND (abfd, _close_and_cleanup, (abfd)) != true) return false; + + bfd_cache_close(abfd); +/* If the file was open for writing and is now executable + make it so */ + if (abfd->direction == write_direction + && abfd->flags & EXEC_P) { + struct stat buf; + stat(abfd->filename, &buf); + chmod(abfd->filename,buf.st_mode | S_IXUSR | S_IXGRP | S_IXOTH); + } + free (abfd); + return true; +} +/* + called to create a bfd with no ascociated file or target + */ +bfd * +bfd_create(filename, template) +char *filename; +bfd *template; +{ + bfd *nbfd = new_bfd(); + if (nbfd == (bfd *)NULL) { + bfd_error = no_memory; + return (bfd *)NULL; + } + nbfd->filename = filename; + nbfd->xvec = template->xvec; + nbfd->direction = no_direction; + return nbfd; + + + +} diff --git a/bfd/srec.c b/bfd/srec.c new file mode 100644 index 00000000000..3ac8e59b619 --- /dev/null +++ b/bfd/srec.c @@ -0,0 +1,464 @@ +/* Copyright (C) 1990, 1991 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Diddler. + +BFD 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 1, or (at your option) +any later version. + +BFD 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 BFD; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + + bfd backend for srecord objects. + + Srecords cannot hold anything but addresses and data, so that's all + that we impliment. + + The only interesting thing is that srecords may come out of order and + there is no header, so an initial scan is required to discover the + minimum and maximum addresses used to create the vma and size of the + only section we create. We arbitarily call this section ".text". + + When bfd_get_section_contents is called the file is read again, and + this time the data is placed into a malloced area. + + Any number of sections may be created for output, we just output them + in the order provided to bfd_set_section_contents. + + + Steve Chamberlain steve@cygnus.com + + */ + + +/* $Id$ + * $Log$ + * Revision 1.1 1991/03/21 21:11:20 gumby + * Initial revision + * + * Revision 1.1 1991/03/13 00:22:29 chrisb + * Initial revision + * + * Revision 1.3 1991/03/10 19:11:40 rich + * Modified Files: + * bfd.c coff-code.h libbfd.c libbfd.h srec.c sunos.c + * + * Working bugs out of coff support. + * + * Revision 1.2 1991/03/07 02:26:18 sac + * Tidied up xfer table + * + * Revision 1.1 1991/03/05 16:28:12 sac + * Initial revision + * + */ + +#include "libbfd.h" + + +static char digs[] = "0123456789ABCDEF"; + +/* Macros for converting between hex and binary */ + +#define NIBBLE(x) ((x >= '0' && x <= '9') ? (x - '0') : (x - 'A' + 10)) +#define HEX(buffer) ((NIBBLE((buffer)->high) <<4) + NIBBLE((buffer)->low)) +#define TOHEX(d,x) \ + ((d)->low = digs[(x) & 0xf], (d)->high = digs[((x)>>4)&0xf], x) + +typedef struct { + char high; + char low; +} byte_as_two_char_type; + +/* The maximum number of bytes on a line is FF */ +#define MAXCHUNK 0xff +/* The number of bytes we fit onto a line on output */ +#define CHUNK 16 + +/* The shape of an srecord .. */ +typedef struct +{ + char S; + char type; + byte_as_two_char_type size; + union { + struct { + byte_as_two_char_type address[4]; + byte_as_two_char_type data[MAXCHUNK]; + /* If there isn't MAXCHUNK bytes of data then the checksum will + appear earlier */ + byte_as_two_char_type checksum; + char nl; + } type_3; + struct { + byte_as_two_char_type address[4]; + byte_as_two_char_type data[MAXCHUNK]; + byte_as_two_char_type checksum; + char nl; + } type_6; + + struct { + byte_as_two_char_type address[3]; + byte_as_two_char_type data[MAXCHUNK]; + byte_as_two_char_type checksum; + char nl; + } type_2; + + struct { + byte_as_two_char_type address[2]; + byte_as_two_char_type data[MAXCHUNK]; + byte_as_two_char_type checksum; + char nl; + } type_1; + byte_as_two_char_type data[MAXCHUNK]; + } u; +} srec_type; + + +/* + called once per input srecord, used to work out vma and size of data. + */ + +static void +size_srec(abfd, section, address, raw, length) +bfd *abfd; +asection *section; +bfd_vma address; +byte_as_two_char_type *raw; +unsigned int length; +{ + if (address < section->vma) + section->vma = address; + + if (address + length > section->vma + section->size) + section->size = (address+length) - section->vma; +} + +/* + called once per input srecord, copies data from input into malloced area + */ + +static void +fillup(abfd, section, address, raw, length) +bfd *abfd; +asection *section; +bfd_vma address; +byte_as_two_char_type *raw; +unsigned int length; +{ + unsigned int i; + bfd_byte *dst = (bfd_byte *)(section->used_by_bfd) + address - section->vma; + for (i = 0; i < length; i++) { + *dst = HEX(raw); + dst++; + raw++; + } +} + +/* + pass over an srecord file calling one of the above functions on each + record + */ +static void +pass_over(abfd, func, section) +bfd *abfd; +void (*func)(); +asection *section; +{ + unsigned int bytes_on_line; + boolean eof = false; + bfd_vma address; + /* To the front of the file */ + bfd_seek(abfd, (file_ptr)0, SEEK_SET); + while (eof == false) + { + srec_type buffer; + + /* Find first 'S' */ + eof = bfd_read(&buffer.S, 1, 1, abfd) != 1; + while (buffer.S != 'S' && !eof) { + eof = bfd_read(&buffer.S, 1, 1, abfd) != 1; + } + if (eof) break; + + bfd_read(&buffer.type, 1, 3, abfd); + + bytes_on_line = HEX(&buffer.size); + + bfd_read(buffer.u.data, 1 , bytes_on_line * 2, abfd); + + switch (buffer.type) { + case '6': + /* Prologue - ignore */ + break; + case '3': + address = (HEX(buffer.u.type_3.address+0) << 24) + + (HEX(buffer.u.type_3.address+1) << 16) + + (HEX(buffer.u.type_3.address+2) << 8) + + (HEX(buffer.u.type_3.address+3)); + func(abfd,section, address, buffer.u.type_2.data, bytes_on_line -1); + + break; + + case '2': + address = (HEX(buffer.u.type_2.address+0) << 16)+ + (HEX(buffer.u.type_2.address+1) << 8) + + (HEX(buffer.u.type_2.address+2)); + func(abfd,section, address, buffer.u.type_2.data, bytes_on_line -1); + + break; + case '1': + address = + (HEX(buffer.u.type_1.address+0) << 8) + + (HEX(buffer.u.type_1.address+1)); + func(abfd, section, address, buffer.u.type_1.data, bytes_on_line -1); + break; + + } + } +} + + +bfd_target * +srec_object_p (abfd) +bfd *abfd; +{ + char b; + asection *section; + bfd_seek(abfd, (file_ptr)0, SEEK_SET); + bfd_read(&b, 1,1,abfd); + if (b != 'S') return (bfd_target*)NULL; + + /* + We create one section called data for all the contents, + and allocate enough room for the entire file + */ + + + section = bfd_make_section(abfd, ".text"); + section->size = 0; + section->vma = 0xffffffff; + pass_over(abfd, size_srec, section); + + return abfd->xvec; +} + + + + + + + + +static boolean +srec_get_section_contents (abfd, section, location, offset, count) +bfd *abfd; +sec_ptr section; +void *location; +file_ptr offset; +unsigned int count; +{ + if (section->used_by_bfd == (bfd_byte *)NULL) { + section->used_by_bfd = (bfd_byte *)malloc(section->size); + pass_over(abfd, fillup, section); + } + (void) memcpy(location, (bfd_byte *)(section->used_by_bfd) + offset, count); + return true; +} + + + +boolean +srec_set_arch_mach (abfd, arch, machine) +bfd *abfd; +enum bfd_architecture arch; +unsigned long machine; +{ + abfd->obj_arch = arch; + abfd->obj_machine = machine; + return true; +} + + + +boolean +srec_set_section_contents (abfd, section, location, offset, bytes_to_do) +bfd *abfd; +sec_ptr section; +unsigned char *location; +file_ptr offset; +int bytes_to_do; +{ + bfd_vma address; + int bytes_written; + + int type; + unsigned int i; + srec_type buffer; + bytes_written = 0; + if (section->size <= 0xffff) + type = 1; + else if (section->size <= 0xffffff) + type = 2; + else + type = 3; + + buffer.S = 'S'; + buffer.type = '0' + type; + + while (bytes_written < bytes_to_do) { + unsigned int size; + unsigned int check_sum; + byte_as_two_char_type *data; + int bytes_this_chunk = bytes_to_do - bytes_written; + + if (bytes_this_chunk > CHUNK) { + bytes_this_chunk = CHUNK; + } + + address = section->vma + offset + bytes_written; + + switch (type) { + case 3: + check_sum = TOHEX(buffer.u.type_3.address, address >> 24); + check_sum += TOHEX(buffer.u.type_3.address+1, address >> 16); + check_sum += TOHEX(buffer.u.type_3.address+2, address >> 8); + check_sum += TOHEX(buffer.u.type_3.address+3, address >> 0); + size = bytes_this_chunk + 5; + data = buffer.u.type_3.data; + + case 2: + check_sum = TOHEX(buffer.u.type_3.address, address >> 16); + check_sum += TOHEX(buffer.u.type_3.address+1, address >> 8); + check_sum += TOHEX(buffer.u.type_3.address+2, address >> 0); + size = bytes_this_chunk + 4; + data = buffer.u.type_2.data; + break; + + case 1: + check_sum = TOHEX(buffer.u.type_3.address+0, address >> 8); + check_sum += TOHEX(buffer.u.type_3.address+1, address >> 0); + size = bytes_this_chunk + 3; + data = buffer.u.type_1.data; + } + + for (i = 0; i < bytes_this_chunk; i++) { + check_sum += TOHEX(data, (location[i])); + data++; + } + + check_sum += TOHEX(&(buffer.size), size ); + (void) TOHEX(data, ~check_sum); + data++; + + * ( (char *)(data)) = '\n'; + bfd_write(&buffer, 1, (char *)data - (char *)&buffer + 1 , abfd); + + bytes_written += bytes_this_chunk; + location += bytes_this_chunk; + } + + + return true; +} + + +boolean +srec_close_and_cleanup (abfd) +bfd *abfd; +{ + asection *s; + if (bfd_read_p (abfd) == false) { + switch (abfd->format) { + case bfd_archive: + if (!_bfd_write_archive_contents (abfd)) { + return false; + } + break; + case bfd_object: + bfd_write("S9030000FC\n", 1,11,abfd); + break; + default: + bfd_error = invalid_operation; + return false; + } + } + for (s = abfd->sections; s != (asection *)NULL;s = s->next) { + if (s->used_by_bfd != (void *)NULL) { + free(s->used_by_bfd); + } + } + return true; +} + +/*SUPPRESS 460 */ +bfd_target srec_vec = +{ + "srec", /* name */ + bfd_target_srec_flavour_enum, + true, /* target byte order */ + true, /* target headers byte order */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED), + (SEC_CODE|SEC_DATA|SEC_ROM + |SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* valid reloc types */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + srec_close_and_cleanup, /* _close_and_cleanup */ + srec_set_section_contents, /* bfd_set_section_contents */ + srec_get_section_contents, + bfd_true, /* new_section_hook */ + 0, /* _core_file_failing_command */ + 0, /* _core_file_failing_signal */ + 0, /* _core_file_matches_ex...p */ + + bfd_false, /* bfd_slurp_armap */ + bfd_false, /* bfd_slurp_extended_name_table */ + bfd_void, /* bfd_truncate_arname */ + bfd_0u, /* get_symtab_upper_bound */ + bfd_0u, /* canonicalize_symtab */ + bfd_void, /* bfd_reclaim_symbol_table */ + bfd_0u, /* get_reloc_upper_bound */ + bfd_0u, /* bfd_canonicalize_reloc */ + bfd_void, /* bfd_reclaim_reloc */ + bfd_0, /* bfd_get_symcount_upper_bound */ + (symindex (*)())bfd_0, /* bfd_get_first_symbol */ + (symindex (*)())bfd_0, /* bfd_get_next_symbol */ + bfd_false, /* bfd_classify_symbol */ + bfd_false, /* bfd_symbol_hasclass */ + (char* (*)())bfd_0, /* bfd_symbol_name */ + bfd_0, /* bfd_symbol_value */ + + _do_getblong, _do_putblong, _do_getbshort, _do_putbshort, /* data */ + _do_getblong, _do_putblong, _do_getbshort, _do_putbshort, /* hdrs */ + + {_bfd_dummy_target, + srec_object_p, /* bfd_check_format */ + (struct bfd_target *(*)()) bfd_nullvoidptr, + (struct bfd_target *(*)()) bfd_nullvoidptr, + }, + { + bfd_false, + bfd_true, /* mkobject */ + _bfd_generic_mkarchive, + bfd_false, + }, + (asymbol * (*)()) bfd_nullvoidptr, /* bfd_make_empty_symbol */ + bfd_void, /* bfd_prit_symbol */ + (alent *(*)())bfd_nullvoidptr, /* srec_get_lineno,*/ + srec_set_arch_mach, /* bfd_set_arch_mach,*/ + bfd_false, /* write_armap*/ + (bfd *(*)())bfd_nullvoidptr, /* openr_next_archived_file */ + bfd_false, /* bfd_find_nearest_line */ +}; diff --git a/bfd/sunos.c b/bfd/sunos.c new file mode 100644 index 00000000000..f857897819e --- /dev/null +++ b/bfd/sunos.c @@ -0,0 +1,1904 @@ +/*** bfd backend for sunos binaries */ + +/* Copyright (C) 1990, 1991 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Diddler. + +BFD 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 1, or (at your option) +any later version. + +BFD 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 BFD; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* $Id$ + * $Log$ + * Revision 1.1 1991/03/21 21:11:23 gumby + * Initial revision + * + * Revision 1.2 1991/03/15 18:16:52 rich + * *** empty log message *** + * + * Revision 1.12 1991/03/10 19:11:41 rich + * Modified Files: + * bfd.c coff-code.h libbfd.c libbfd.h srec.c sunos.c + * + * Working bugs out of coff support. + * + * Revision 1.11 1991/03/09 03:40:04 rich + * Modified Files: + * Makefile b.out.c liba.out.h libbfd.c sunos.c sysdep.h + * + * Changes dictated by porting binutils. + * + * Revision 1.10 1991/03/08 07:52:02 sac + * Reinstalled things which went away after latest merge from Intel. + * + * Fixed a couple of problems in symbol handling too. + * + * Revision 1.9 1991/03/08 04:18:16 rich + * *** empty log message *** + * + * Revision 1.8 1991/03/07 21:57:26 sac + * Moved type info out of the asymbol into the private space. + * Cleaned up C++ stuff + * + * Revision 1.7 1991/03/06 21:49:02 sac + * Modified bfd_find_filename to return name of function too. + * + * Revision 1.6 1991/03/06 02:19:36 sac + * Moved howto table, added support for constructor sections and provided + * sunos4_find_nearest_line + * + * Revision 1.5 1991/03/05 16:25:44 sac + * Modified howto vector to include inplace and mask fields. + * + */ + +#define TARGET_BYTE_ORDER_BIG_P 1 +#define TARGET TARGET_SPARC + +#include "sysdep.h" +#include "bfd.h" +#include "libbfd.h" +#include + + +/*SUPPRESS558*/ +/*SUPPRESS529*/ + + + + +typedef void generic_symbol_type; +/* These values are correct for the SPARC. I dunno about anything else */ +#define PAGE_SIZE 0x02000 +#define SEGMENT_SIZE PAGE_SIZE +#define TEXT_START_ADDR PAGE_SIZE +#include "a.out.gnu.h" +#include "stab.gnu.h" +#include "ar.h" +#include "liba.out.h" /* BFD a.out internal data structures */ + +#include "a.out.sun4.h" + +#define CTOR_TABLE_RELOC_IDX 2 +static reloc_howto_type howto_table[] = +{ + /* type rs size bsz pcrel bitpos abs ovrf sf name partial inplace mask*/ +{ (unsigned int) RELOC_8, 0, 0, 8, false, 0, true, true,0,"8", false, 0x000000ff}, +{ (unsigned int) RELOC_16, 0, 1, 16, false, 0, true, true,0,"16", false, 0x0000ffff}, +{ (unsigned int) RELOC_32, 0, 2, 32, false, 0, true, true,0,"32", false, 0xffffffff}, +{ (unsigned int) RELOC_DISP8, 0, 0, 8, true, 0, false, true,0,"DISP8", false, 0x000000ff}, +{ (unsigned int) RELOC_DISP16, 0, 1, 16, true, 0, false, true,0,"DISP16", false, 0x0000ffff}, +{ (unsigned int) RELOC_DISP32, 0, 2, 32, true, 0, false, true,0,"DISP32", false, 0xffffffff}, +{ (unsigned int) RELOC_WDISP30,2, 2, 30, true, 0, false, true,0,"WDISP30", false, 0x3fffffff}, +{ (unsigned int) RELOC_WDISP22,2, 2, 22, true, 0, false, true,0,"WDISP22", false, 0x003fffff}, +{ (unsigned int) RELOC_HI22, 10, 2, 22, false, 0, false, true,0,"HI22", false, 0x003fffff}, +{ (unsigned int) RELOC_22, 0, 2, 22, false, 0, false, true,0,"22", false, 0x003fffff}, +{ (unsigned int) RELOC_13, 0, 2, 13, false, 0, false, true,0,"13", false, 0x00001fff}, +{ (unsigned int) RELOC_LO10, 0, 2, 10, false, 0, false, true,0,"LO10", false, 0x000003ff}, +{ (unsigned int) RELOC_SFA_BASE,0, 2, 32, false, 0, false, true,0,"SFA_BASE", false, 0xffffffff}, +{ (unsigned int) RELOC_SFA_OFF13,0,2, 32, false, 0, false, true,0,"SFA_OFF13",false, 0xffffffff}, +{ (unsigned int) RELOC_BASE10, 0, 2, 16, false, 0, false, true,0,"BASE10", false, 0x0000ffff}, +{ (unsigned int) RELOC_BASE13, 0, 2, 13, false, 0, false, true,0,"BASE13", false, 0x00001fff}, +{ (unsigned int) RELOC_BASE22, 0, 2, 0, false, 0, false, true,0,"BASE22", false, 0x00000000}, +{ (unsigned int) RELOC_PC10, 0, 2, 10, false, 0, false, true,0,"PC10", false, 0x000003ff}, +{ (unsigned int) RELOC_PC22, 0, 2, 22, false, 0, false, true,0,"PC22", false, 0x003fffff}, +{ (unsigned int) RELOC_JMP_TBL,0, 2, 32, false, 0, false, true,0,"JMP_TBL", false, 0xffffffff}, +{ (unsigned int) RELOC_SEGOFF16,0, 2, 0, false, 0, false, true,0,"SEGOFF16", false, 0x00000000}, +{ (unsigned int) RELOC_GLOB_DAT,0, 2, 0, false, 0, false, true,0,"GLOB_DAT", false, 0x00000000}, +{ (unsigned int) RELOC_JMP_SLOT,0, 2, 0, false, 0, false, true,0,"JMP_SLOT", false, 0x00000000}, +{ (unsigned int) RELOC_RELATIVE,0, 2, 0, false, 0, false, true,0,"RELATIVE", false, 0x00000000}, +{ (unsigned int) RELOC_JUMPTARG,2, 13, 16, true, 0, false, true,0,"JUMPTARG", false, 0x0000ffff}, +{ (unsigned int) RELOC_CONST, 0, 13, 16, false, 0, false, true,0,"CONST", false, 0x0000ffff}, +{ (unsigned int) RELOC_CONSTH, 16, 13, 16, false, 0, false, true,0,"CONSTH", false, 0x0000ffff}, +}; + +/** a.out files */ + +PROTO (static void, swap_exec_header, (bfd *abfd, struct exec *execp)); +PROTO (void , sunos4_write_syms, ()); +PROTO (static boolean,sunos4_squirt_out_relocs,(bfd *abfd, asection *section)); + +/* Steve wants some way to frob this stuff from Saber while he's debugging + ld, so we have these funny shadow functions */ +/* ZMAGIC's start at 0 (making the exec part of the text section), + other formats start after the exec +*/ +unsigned int n_txtoff(ptr) +struct exec *ptr; +{return N_MAGIC(*ptr)== ZMAGIC ? 0: sizeof(struct exec);} + +unsigned int n_datoff(ptr) +struct exec *ptr; +{return n_txtoff(ptr) + ptr->a_text;} + +unsigned int n_treloff(ptr) +struct exec *ptr; +{return n_datoff(ptr) + ptr->a_data;} + +unsigned int n_dreloff(ptr) +struct exec *ptr; +{return n_treloff(ptr) + ptr->a_trsize;} + +unsigned int n_symoff(ptr) +struct exec *ptr; +{return n_dreloff(ptr) + ptr->a_drsize;} + +unsigned int n_stroff(ptr) +struct exec *ptr; +{return n_symoff(ptr) + ptr->a_syms;} + +unsigned int n_badmag(ptr) + struct exec *ptr; +{ + switch (N_MAGIC(*ptr)) { + case OMAGIC: case NMAGIC: case ZMAGIC: return 0; + default: return 1; + } +} + + +bfd_target * +sunos4_object_p (abfd) + bfd *abfd; +{ + unsigned long magic; + struct exec anexec; /* save consing when you don't have to. */ + struct exec *execp = &anexec; + void *rawptr; + + bfd_error = system_call_error; + + if (bfd_read ((void *)&magic, 1, sizeof (magic), abfd) != sizeof (magic)) + return 0; + magic = bfd_h_getlong (abfd, &magic); + + /* Baroque syntax to mask deficiencies of the Sun compiler */ + /* if (N_BADMAG (*((struct exec *) &magic))) return 0; */ + if (n_badmag ((struct exec *) &magic)) return 0; + + if (bfd_seek (abfd, 0L, SEEK_SET) < 0) return 0; + + if (bfd_read ((void *) execp, 1, sizeof (struct exec), abfd) + != sizeof (struct exec)) { + bfd_error = wrong_format; + return 0; + } + + /* Use an intermediate variable for clarity */ + rawptr = (void *) zalloc (sizeof (struct sunexdata) + sizeof (struct exec)); + + if (rawptr == NULL) { + bfd_error = no_memory; + return 0; + } + + abfd->tdata =(void *)( (struct sunexdata *) rawptr); + exec_hdr (abfd) = + (struct exec *) ((char *)rawptr + sizeof (struct sunexdata)); + + swap_exec_header (abfd, execp); + memcpy (exec_hdr (abfd), execp, sizeof (struct exec)); + + /* Set the file flags */ + abfd->flags = NO_FLAGS; + if (execp->a_drsize || execp->a_trsize) + abfd->flags |= HAS_RELOC; + if (execp->a_entry) + abfd->flags |= EXEC_P; + if (execp->a_syms) + abfd->flags |= HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS; + + + if (N_MAGIC (anexec) == ZMAGIC) abfd->flags |= D_PAGED; + if (N_MAGIC (anexec) == NMAGIC) abfd->flags |= WP_TEXT; + + /* Determine the architecture and machine type of the object file. */ + abfd->obj_arch = bfd_arch_unknown; /* Default values */ + abfd->obj_machine = 0; + switch (N_MACHTYPE (anexec)) { + + case M_UNKNOWN: + break; + + case M_68010: + abfd->obj_arch = bfd_arch_m68k; + abfd->obj_machine = 68010; + break; + + case M_68020: + abfd->obj_arch = bfd_arch_m68k; + abfd->obj_machine = 68020; + break; + + case M_SPARC: + abfd->obj_arch = bfd_arch_sparc; + break; + + case M_386: + abfd->obj_arch = bfd_arch_i386; + break; + + case M_29K: + abfd->obj_arch = bfd_arch_a29k; + break; + + default: + abfd->obj_arch = bfd_arch_obscure; + break; + } + + bfd_get_start_address (abfd) = execp->a_entry; + + /* Remember the positions of the string table and symbol table. */ + obj_str_filepos (abfd) = n_stroff (&anexec); + obj_sym_filepos (abfd) = n_symoff (&anexec); + + /* create the sections. This is raunchy, but bfd_close wants to reclaim + them */ + obj_textsec (abfd) = (asection *)NULL; + obj_datasec (abfd) = (asection *)NULL; + obj_bsssec (abfd) = (asection *)NULL; + obj_aout_symbols(abfd) = (aout_symbol_type *)NULL; + (void)bfd_make_section(abfd, ".text"); + (void)bfd_make_section(abfd, ".data"); + (void)bfd_make_section(abfd, ".bss"); + + obj_datasec (abfd)->size = execp->a_data; + obj_bsssec (abfd)->size = execp->a_bss; + obj_textsec (abfd)->size = execp->a_text; + obj_datasec (abfd)->vma = N_DATADDR(anexec); + obj_bsssec (abfd)->vma = N_BSSADDR(anexec); + obj_textsec (abfd)->vma = N_TXTADDR(anexec); + + obj_textsec (abfd)->filepos = n_txtoff(&anexec); + obj_datasec (abfd)->filepos = n_datoff(&anexec); + + obj_textsec (abfd)->rel_filepos = n_treloff(&anexec); + obj_datasec (abfd)->rel_filepos = n_dreloff(&anexec); + + obj_textsec (abfd)->flags = + (execp->a_trsize != 0 ? + (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_HAS_CONTENTS) : + (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS)); + obj_datasec (abfd)->flags = + (execp->a_drsize != 0 ? + (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_HAS_CONTENTS) : + (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS)); + obj_bsssec (abfd)->flags = SEC_ALLOC; + + abfd->sections = obj_textsec (abfd); + obj_textsec (abfd)->next = obj_datasec (abfd); + obj_datasec (abfd)->next = obj_bsssec (abfd); + return abfd->xvec; +} + + +boolean +sunos4_mkobject (abfd) + bfd *abfd; +{ + char *rawptr; + + bfd_error = system_call_error; + + /* Use an intermediate variable for clarity */ + rawptr = zalloc (sizeof (struct sunexdata) + sizeof (struct exec)); + + if (rawptr == NULL) { + bfd_error = no_memory; + return false; + } + + abfd->tdata = (void *)((struct sunexdata *) rawptr); + exec_hdr (abfd) = (struct exec *) (rawptr + sizeof (struct sunexdata)); + + /* For simplicity's sake we just make all the sections right here. */ + + obj_textsec (abfd) = (asection *)NULL; + obj_datasec (abfd) = (asection *)NULL; + obj_bsssec (abfd) = (asection *)NULL; + bfd_make_section (abfd, ".text"); + bfd_make_section (abfd, ".data"); + bfd_make_section (abfd, ".bss"); + + return true; +} + +/* Keep track of machine architecture and machine type for a.out's. + Return the machine_type for a particular arch&machine, or M_UNKNOWN + if that exact arch&machine can't be represented in a.out format. + + If the architecture is understood, machine type 0 (default) should + always be understood. */ + +static enum machine_type +aout_machine_type (arch, machine) + enum bfd_architecture arch; + unsigned long machine; +{ + enum machine_type arch_flags; + + arch_flags = M_UNKNOWN; + + switch (arch) { + case bfd_arch_sparc: + if (machine == 0) arch_flags = M_SPARC; + break; + + case bfd_arch_m68k: + switch (machine) { + case 0: arch_flags = M_UNKNOWN; break; + case 68000: arch_flags = M_UNKNOWN; break; + case 68010: arch_flags = M_68010; break; + case 68020: arch_flags = M_68020; break; + default: arch_flags = M_UNKNOWN; break; + } + break; + + case bfd_arch_i386: + if (machine == 0) arch_flags = M_386; + break; + + case bfd_arch_a29k: + if (machine == 0) arch_flags = M_29K; + break; + + default: + arch_flags = M_UNKNOWN; + break; + } + return arch_flags; +} + +boolean +sunos4_set_arch_mach (abfd, arch, machine) + bfd *abfd; + enum bfd_architecture arch; + unsigned long machine; +{ + abfd->obj_arch = arch; + abfd->obj_machine = machine; + if (arch != bfd_arch_unknown && + aout_machine_type (arch, machine) == M_UNKNOWN) + return false; /* We can't represent this type */ + return true; /* We're easy ... */ +} + +boolean +sunos4_write_object_contents (abfd) + bfd *abfd; +{ + int data_pad = 0; + struct exec *execp = exec_hdr (abfd); + + + + /* Magic number, maestro, please! */ + switch (bfd_get_architecture(abfd)) { + case bfd_arch_m68k: + switch (bfd_get_machine(abfd)) { + case 68010: + N_SET_MACHTYPE(*execp, M_68010); + break; + default: + case 68020: + N_SET_MACHTYPE(*execp, M_68020); + break; + } + break; + case bfd_arch_sparc: + N_SET_MACHTYPE(*execp, M_SPARC); + break; + case bfd_arch_i386: + N_SET_MACHTYPE(*execp, M_386); + break; + case bfd_arch_a29k: + N_SET_MACHTYPE(*execp, M_29K); + break; + default: + N_SET_MACHTYPE(*execp, M_UNKNOWN); + } + execp->a_text = obj_textsec (abfd)->size; + N_SET_MAGIC (*execp, OMAGIC); + if (abfd->flags & D_PAGED) { + execp->a_text = obj_textsec (abfd)->size + sizeof(struct exec); + N_SET_MAGIC (*execp, ZMAGIC); + } else if (abfd->flags & WP_TEXT) { + N_SET_MAGIC (*execp, NMAGIC); + } + N_SET_FLAGS (*execp, 0x1); /* copied from ld.c; who the hell knows? */ + + if (abfd->flags & D_PAGED) + { + data_pad = ((obj_datasec(abfd)->size + PAGE_SIZE -1) + & (- PAGE_SIZE)) - obj_datasec(abfd)->size; + + if (data_pad > obj_bsssec(abfd)->size) + execp->a_bss = 0; + else + execp->a_bss = obj_bsssec(abfd)->size - data_pad; + execp->a_data = obj_datasec(abfd)->size + data_pad; + + } + else { + execp->a_data = obj_datasec (abfd)->size; + execp->a_bss = obj_bsssec (abfd)->size; + } + + execp->a_syms = bfd_get_symcount (abfd) * sizeof (struct nlist); + execp->a_entry = bfd_get_start_address (abfd); + execp->a_trsize = ((obj_textsec (abfd)->reloc_count) * + sizeof (struct reloc_info_extended)); + execp->a_drsize = ((obj_datasec (abfd)->reloc_count) * + sizeof (struct reloc_info_extended));; + + swap_exec_header (abfd, execp); + + bfd_seek (abfd, 0L, SEEK_SET); + bfd_write ((void *) execp, 1, sizeof (struct exec), abfd); + + /* Now write out reloc info, followed by syms and strings */ + + if (bfd_get_symcount (abfd) != 0) + { + bfd_seek (abfd, + (long)(N_SYMOFF(*execp)), SEEK_SET); + + sunos4_write_syms (abfd); + + bfd_seek (abfd, (long)(N_TROFF(*execp)), SEEK_SET); + + if (!sunos4_squirt_out_relocs (abfd, obj_textsec (abfd))) return false; + bfd_seek (abfd, (long)(N_DROFF(*execp)), SEEK_SET); + + if (!sunos4_squirt_out_relocs (abfd, obj_datasec (abfd))) return false; + } + return true; +} + +static void +swap_exec_header (abfd, execp) +bfd *abfd; + struct exec *execp; +{ + if (bfd_header_twiddle_required(abfd)) { + /* execp->a_info = bfd_h_getlong (abfd, &execp->a_info); */ + *(unsigned long *) execp = + bfd_h_getlong (abfd, (unsigned long *) execp); + execp->a_text = bfd_h_getlong (abfd, &execp->a_text); + execp->a_data = bfd_h_getlong (abfd, &execp->a_data); + execp->a_bss = bfd_h_getlong (abfd, &execp->a_bss); + execp->a_syms = bfd_h_getlong (abfd, &execp->a_syms); + execp->a_entry = bfd_h_getlong (abfd, &execp->a_entry); + execp->a_trsize = bfd_h_getlong (abfd, &execp->a_trsize); + execp->a_drsize = bfd_h_getlong (abfd, &execp->a_drsize); + } +} /* swap_exec_header() */ + +/** core files */ + +#define CORE_MAGIC 0x080456 +#define CORE_NAMELEN 16 + +/* The core structure is taken from the Sun documentation. + Unfortunately, they don't document the FPA structure, or at least I + can't find it easily. Fortunately the core header contains its own + length. So this shouldn't cause problems, except for c_ucode, which + so far we don't use but is easy to find with a little arithmetic. */ + +/* But the reg structure can be gotten from the SPARC processor handbook. + This really should be in a GNU include file though so that gdb can use + the same info. */ +struct regs { + int r_psr; + int r_pc; + int r_npc; + int r_y; + int r_g1; + int r_g2; + int r_g3; + int r_g4; + int r_g5; + int r_g6; + int r_g7; + int r_o0; + int r_o1; + int r_o2; + int r_o3; + int r_o4; + int r_o5; + int r_o6; + int r_o7; +}; + +/* Taken from Sun documentation: */ + +struct core { + int c_magic; /* Corefile magic number */ + int c_len; /* Sizeof (struct core) */ + struct regs c_regs; /* General purpose registers */ + struct exec c_aouthdr; /* A.out header */ + int c_signo; /* Killing signal, if any */ + int c_tsize; /* Text size (bytes) */ + int c_dsize; /* Data size (bytes) */ + int c_ssize; /* Stack size (bytes) */ + char c_cmdname[CORE_NAMELEN + 1]; /* Command name */ + double fp_stuff[1]; /* external FPU state (size unknown by us) */ + /* The type "double" is critical here, for alignment. + SunOS declares a struct here, but the struct's + alignment is double since it contains doubles. */ + int c_ucode; /* Exception no. from u_code */ + /* (this member not accessible by name since we don't + portably know the size of fp_stuff.) */ +}; + +/* Supposedly the user stack grows downward from the bottom of kernel memory. + Presuming that this remains true, this definition will work. */ +#define USRSTACK (-(128*1024*1024)) + +PROTO (static void, swapcore, (bfd *abfd, struct core *core)); + +/* need this cast b/c ptr is really void * */ +#define core_hdr(bfd) (((struct suncordata *) (bfd->tdata))->hdr) +#define core_datasec(bfd) (((struct suncordata *) ((bfd)->tdata))->data_section) +#define core_stacksec(bfd) (((struct suncordata*)((bfd)->tdata))->stack_section) +#define core_regsec(bfd) (((struct suncordata *) ((bfd)->tdata))->reg_section) +#define core_regsec2(bfd) (((struct suncordata *) ((bfd)->tdata))->reg2_section) + +/* These are stored in the bfd's tdata */ +struct suncordata { + struct core *hdr; /* core file header */ + asection *data_section; + asection *stack_section; + asection *reg_section; + asection *reg2_section; +}; + +bfd_target * +sunos4_core_file_p (abfd) + bfd *abfd; +{ + /* includes redundent variables for code clarity */ + int core_size; + int core_mag; + struct core *core; + char *rawptr; + + bfd_error = system_call_error; + + if (bfd_read ((void *)&core_mag, 1, sizeof (int), abfd) != sizeof (int)) + return 0; + core_mag = bfd_h_getlong(abfd, &core_mag); + + if (core_mag != CORE_MAGIC) return 0; + + /* SunOS core headers can vary in length; second word is size; */ + if (bfd_read ((void *)&core_size, 1, sizeof (int), abfd) != sizeof (int)) + return 0; + core_size = bfd_h_getlong(abfd, &core_size); + + if (bfd_seek (abfd, 0L, SEEK_SET) < 0) return 0; + + rawptr = zalloc (core_size + sizeof (struct suncordata)); + if (rawptr == NULL) { + bfd_error = no_memory; + return 0; + } + + core = (struct core *) (rawptr + sizeof (struct suncordata)); + + if ((bfd_read ((void *) core, 1, core_size, abfd)) != core_size) { + bfd_error = system_call_error; + free ((void *)rawptr); + return 0; + } + + swapcore (abfd, core); + abfd->tdata = (void *)((struct suncordata *) rawptr); + core_hdr (abfd) = core; + + /* create the sections. This is raunchy, but bfd_close wants to reclaim + them */ + core_stacksec (abfd) = (asection *) zalloc (sizeof (asection)); + if (core_stacksec (abfd) == NULL) { + loser: + bfd_error = no_memory; + free ((void *)rawptr); + return 0; + } + core_datasec (abfd) = (asection *) zalloc (sizeof (asection)); + if (core_datasec (abfd) == NULL) { + loser1: + free ((void *)core_stacksec (abfd)); + goto loser; + } + core_regsec (abfd) = (asection *) zalloc (sizeof (asection)); + if (core_regsec (abfd) == NULL) { + loser2: + free ((void *)core_datasec (abfd)); + goto loser1; + } + core_regsec2 (abfd) = (asection *) zalloc (sizeof (asection)); + if (core_regsec2 (abfd) == NULL) { + free ((void *)core_regsec (abfd)); + goto loser2; + } + + core_stacksec (abfd)->name = ".stack"; + core_datasec (abfd)->name = ".data"; + core_regsec (abfd)->name = ".reg"; + core_regsec2 (abfd)->name = ".reg2"; + + core_stacksec (abfd)->flags = SEC_ALLOC + SEC_LOAD; + core_datasec (abfd)->flags = SEC_ALLOC + SEC_LOAD; + core_regsec (abfd)->flags = SEC_ALLOC; + core_regsec2 (abfd)->flags = SEC_ALLOC; + + core_stacksec (abfd)->size = core->c_ssize; + core_datasec (abfd)->size = core->c_dsize; + core_regsec (abfd)->size = (sizeof core->c_regs); + /* Float regs take up end of struct, except c_ucode. */ + core_regsec2 (abfd)->size = core_size - (sizeof core->c_ucode) - + (file_ptr)(((struct core *)0)->fp_stuff); + + core_stacksec (abfd)->vma = (USRSTACK - core->c_ssize); + core_datasec (abfd)->vma = N_DATADDR(core->c_aouthdr); + core_regsec (abfd)->vma = -1; + core_regsec2 (abfd)->vma = -1; + + core_stacksec (abfd)->filepos = core->c_len + core->c_dsize; + core_datasec (abfd)->filepos = core->c_len; + /* In file header: */ + core_regsec (abfd)->filepos = (file_ptr)(&((struct core *)0)->c_regs); + core_regsec2 (abfd)->filepos = (file_ptr)(((struct core *)0)->fp_stuff); + + /* Align to word at least */ + core_stacksec (abfd)->alignment_power = 2; + core_datasec (abfd)->alignment_power = 2; + core_regsec (abfd)->alignment_power = 2; + core_regsec2 (abfd)->alignment_power = 2; + + abfd->sections = core_stacksec (abfd); + core_stacksec (abfd)->next = core_datasec (abfd); + core_datasec (abfd)->next = core_regsec (abfd); + core_regsec (abfd)->next = core_regsec2 (abfd); + + abfd->section_count = 4; + + return abfd->xvec; +} + +char * +sunos4_core_file_failing_command (abfd) + bfd *abfd; +{ + return core_hdr (abfd)->c_cmdname; +} + +int +sunos4_core_file_failing_signal (abfd) + bfd *abfd; +{ + return core_hdr (abfd)->c_signo; +} + +boolean +sunos4_core_file_matches_executable_p (core_bfd, exec_bfd) + bfd *core_bfd, *exec_bfd; +{ + if (core_bfd->xvec != exec_bfd->xvec) { + bfd_error = system_call_error; + return false; + } + + return (bcmp (&core_hdr (core_bfd), &exec_hdr (exec_bfd), + sizeof (struct exec)) == 0) ? true : false; +} + +/* byte-swap core structure */ +static void +swapcore (abfd, core) +bfd *abfd; + struct core *core; +{ + if (bfd_header_twiddle_required(abfd)) { + core->c_magic = bfd_h_getlong (abfd, &core->c_magic); + core->c_len = bfd_h_getlong (abfd, &core->c_len); + /* regs */ + swap_exec_header (abfd, &(core->c_aouthdr)); + core->c_signo = bfd_h_getlong (abfd, &core->c_signo); + core->c_tsize = bfd_h_getlong (abfd, &core->c_tsize); + core->c_dsize = bfd_h_getlong (abfd, &core->c_dsize); + core->c_ssize = bfd_h_getlong (abfd, &core->c_ssize); + core->c_ucode = bfd_h_getlong (abfd, &core->c_ucode); + /* I don't understand how to swap an FP register */ + } +} + +/** exec and core file sections */ + +boolean +sunos4_new_section_hook (abfd, newsect) + bfd *abfd; + asection *newsect; +{ + /* align to double at least */ + newsect->alignment_power = 3; + + if (bfd_get_format (abfd) == bfd_object) { + if (obj_textsec(abfd) == NULL && !strcmp(newsect->name, ".text")) { + obj_textsec(abfd)= newsect; + return true; + } + + if (obj_datasec(abfd) == NULL && !strcmp(newsect->name, ".data")) { + obj_datasec(abfd) = newsect; + return true; + } + + if (obj_bsssec(abfd) == NULL && !strcmp(newsect->name, ".bss")) { + obj_bsssec(abfd) = newsect; + return true; + } + } + +#if 0 /* FIXME -- this is temporary for steve */ + bfd_error = invalid_operation; + + return false; +#endif + + /* We allow more than three sections internally */ + return true; +} + +boolean +sunos4_set_section_contents (abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + unsigned char *location; + file_ptr offset; + int count; +{ + if (abfd->output_has_begun == false) + { /* set by bfd.c handler */ + if ((obj_textsec (abfd) == NULL) || (obj_datasec (abfd) == NULL) + + /*|| + (obj_textsec (abfd)->size == 0) || (obj_datasec (abfd)->size= + 0)*/ + ) + { + bfd_error = invalid_operation; + return false; + } + + +#if 0 + if (abfd->flags & D_PAGED) + { + obj_textsec (abfd)->filepos = sizeof(struct exec); + obj_datasec(abfd)->filepos = obj_textsec (abfd)->size; + } + else +#endif +{ + obj_textsec (abfd)->filepos = sizeof(struct exec); + obj_datasec(abfd)->filepos = obj_textsec(abfd)->filepos + obj_textsec (abfd)->size; + + } + } + /* regardless, once we know what we're doing, we might as well get going */ + + bfd_seek (abfd, section->filepos + offset, SEEK_SET); + + if (count) { + return (bfd_write ((void *)location, 1, count, abfd) == count) ? true : false; + } + return false; +} +boolean +sunos4_get_section_contents (abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + void *location; + file_ptr offset; + int count; +{ + if (count) { + if (offset >= section->size) return false; + + bfd_seek (abfd, section->filepos + offset, SEEK_SET); + + return (bfd_read (location, 1, count, abfd) == count) ? true:false; + } + else return true; +} + + +/* Classify stabs symbols */ + + +#define sym_in_text_section(sym) \ + (((sym)->n_type & (N_ABS | N_TEXT | N_DATA | N_BSS))== N_TEXT) + +#define sym_in_data_section(sym) \ + (((sym)->n_type & (N_ABS | N_TEXT | N_DATA | N_BSS))== N_DATA) + +#define sym_in_bss_section(sym) \ + (((sym)->n_type & (N_ABS | N_TEXT | N_DATA | N_BSS))== N_BSS) + +/* Symbol is undefined if type is N_UNDF|N_EXT and if it has + zero in the "value" field. Nonzeroes there are fortrancommon + symbols. */ +#define sym_is_undefined(sym) \ + ((sym)->n_type == (N_UNDF | N_EXT) && (sym)->n_value == 0) + +/* Symbol is a global definition if N_EXT is on and if it has + a nonzero type field. */ +#define sym_is_global_defn(sym) \ + (((sym)->n_type & N_EXT) && (sym)->n_type & N_TYPE) + +/* Symbol is debugger info if any bits outside N_TYPE or N_EXT + are on. */ +#define sym_is_debugger_info(sym) \ + ((sym)->n_type & ~(N_EXT | N_TYPE)) + +#define sym_is_fortrancommon(sym) \ + (((sym)->n_type == (N_EXT)) && (sym)->n_value != 0) + +/* Symbol is absolute if it has N_ABS set */ +#define sym_is_absolute(sym) \ + (((sym)->n_type & N_TYPE)== N_ABS) + + +#define sym_is_indirect(sym) \ + (((sym)->n_type & N_ABS)== N_ABS) + +/* Only in their own functions for ease of debugging; when sym flags have + stabilised these should be inlined into their (single) caller */ + +static void +translate_from_native_sym_flags (sym_pointer, cache_ptr, abfd) + struct nlist *sym_pointer; + aout_symbol_type *cache_ptr; + bfd *abfd; +{ + switch (cache_ptr->type & N_TYPE) { + case N_SETA: + case N_SETT: + case N_SETD: + case N_SETB: + { + asection *section = bfd_make_section(abfd, + cache_ptr->symbol.name); + arelent_chain *reloc = (arelent_chain *)malloc(sizeof(arelent_chain)); + + switch ( (cache_ptr->type & N_TYPE) ) { + case N_SETA: + reloc->relent.section = (asection *)NULL; + cache_ptr->symbol.section = (asection *)NULL; + break; + case N_SETT: + reloc->relent.section = (asection *)obj_textsec(abfd); + cache_ptr->symbol.value -= reloc->relent.section->vma; + break; + case N_SETD: + reloc->relent.section = (asection *)obj_datasec(abfd); + cache_ptr->symbol.value -= reloc->relent.section->vma; + break; + case N_SETB: + reloc->relent.section = (asection *)obj_bsssec(abfd); + cache_ptr->symbol.value -= reloc->relent.section->vma; + break; + } + cache_ptr->symbol.section = reloc->relent.section; + reloc->relent.addend = cache_ptr->symbol.value ; + /* + We modify the symbol to belong to a section depending upon the + name of the symbol - probably __CTOR__ or __DTOR__ but we don't + really care, and add to the size of the section to contain a + pointer to the symbol. Build a reloc entry to relocate to this + symbol attached to this section. + */ + + + section->flags = SEC_CONSTRUCTOR; + section->reloc_count++; + section->alignment_power = 2; + reloc->relent.sym_ptr_ptr = (asymbol **)NULL; + reloc->next = section->constructor_chain; + section->constructor_chain = reloc; + reloc->relent.address = section->size; + section->size += sizeof(int *); + + reloc->relent.howto = howto_table +CTOR_TABLE_RELOC_IDX; + cache_ptr->symbol.flags |= BSF_DEBUGGING ; + } + break; + default: + + if (sym_is_debugger_info (sym_pointer)) { + cache_ptr->symbol.flags = BSF_DEBUGGING ; + /* Work out the section correct for this symbol */ + switch (sym_pointer->n_type & N_TYPE) + { + case N_TEXT: + case N_FN: + cache_ptr->symbol.section = obj_textsec (abfd); + cache_ptr->symbol.value -= obj_textsec(abfd)->vma; + break; + case N_DATA: + cache_ptr->symbol.value -= obj_datasec(abfd)->vma; + cache_ptr->symbol.section = obj_datasec (abfd); + break; + case N_BSS : + cache_ptr->symbol.section = obj_bsssec (abfd); + cache_ptr->symbol.value -= obj_bsssec(abfd)->vma; + break; + case N_ABS: + default: + cache_ptr->symbol.section = 0; + break; + } + } + else { + if (sym_is_fortrancommon (sym_pointer)) + { + cache_ptr->symbol.flags = BSF_FORT_COMM; + cache_ptr->symbol.section = (asection *)NULL; + } + else { + if (sym_is_undefined (sym_pointer)) { + cache_ptr->symbol.flags = BSF_UNDEFINED; + } + else if (sym_is_global_defn (sym_pointer)) { + cache_ptr->symbol.flags = BSF_GLOBAL | BSF_EXPORT; + } + + else if (sym_is_absolute (sym_pointer)) { + cache_ptr->symbol.flags = BSF_ABSOLUTE; + } + else { + cache_ptr->symbol.flags = BSF_LOCAL; + } + + /* In a.out, the value of a symbol is always relative to the + * start of the file, if this is a data symbol we'll subtract + * the size of the text section to get the section relative + * value. If this is a bss symbol (which would be strange) + * we'll subtract the size of the previous two sections + * to find the section relative address. + */ + + if (sym_in_text_section (sym_pointer)) { + cache_ptr->symbol.value -= obj_textsec(abfd)->vma; + cache_ptr->symbol.section = obj_textsec (abfd); + } + else if (sym_in_data_section (sym_pointer)){ + cache_ptr->symbol.value -= obj_datasec(abfd)->vma; + cache_ptr->symbol.section = obj_datasec (abfd); + } + else if (sym_in_bss_section(sym_pointer)) { + cache_ptr->symbol.section = obj_bsssec (abfd); + cache_ptr->symbol.value -= obj_bsssec(abfd)->vma; + } + else { + cache_ptr->symbol.section = (asection *)NULL; + cache_ptr->symbol.flags |= BSF_ABSOLUTE; + } + } + } + } +} +void +translate_to_native_sym_flags (sym_pointer, cache_ptr_g, abfd) + struct nlist *sym_pointer; + generic_symbol_type *cache_ptr_g; + bfd *abfd; +{ + asymbol *cache_ptr = (asymbol *)cache_ptr_g; + + /* FIXME check for wrigin bss */ + if (bfd_get_section(cache_ptr)) { + if (bfd_get_output_section(cache_ptr) == obj_bsssec (abfd)) { + sym_pointer->n_type |= N_BSS; + } + else if (bfd_get_output_section(cache_ptr) == obj_datasec (abfd)) { + sym_pointer->n_type |= N_DATA; + } + else if (bfd_get_output_section(cache_ptr) == obj_textsec (abfd)) { + sym_pointer->n_type |= N_TEXT; + } + else { + BFD_ASSERT(0); + } + /* Turn the symbol from section relative to absolute again */ + sym_pointer->n_value += + cache_ptr->section->output_section->vma + + cache_ptr->section->output_offset ; + } + else { + sym_pointer->n_type |= N_ABS; + } + + if (cache_ptr->flags & (BSF_FORT_COMM | BSF_UNDEFINED)) { + sym_pointer->n_type = (N_UNDF | N_EXT); + return; + } + + if (cache_ptr->flags & BSF_ABSOLUTE) { + sym_pointer->n_type |= N_ABS; + } + + if (cache_ptr->flags & (BSF_GLOBAL | BSF_EXPORT)) { + sym_pointer->n_type |= N_EXT; + } + if (cache_ptr->flags & BSF_DEBUGGING) { + sym_pointer->n_type = ((aout_symbol_type *)cache_ptr)->type; + } + +} + +/* Native-level interface to symbols. */ + +/* We read the symbols into a buffer, which is discarded when this + function exits. We read the strings into a buffer large enough to + hold them all plus all the cached symbol entries. */ + +asymbol * +sunos4_make_empty_symbol (abfd) +bfd *abfd; +{ + aout_symbol_type *new = + (aout_symbol_type *)zalloc (sizeof (aout_symbol_type)); + new->symbol.the_bfd = abfd; + + return &new->symbol; +} + +boolean +sunos4_slurp_symbol_table (abfd) + bfd *abfd; +{ + unsigned int symbol_count; + size_t symbol_size; + size_t string_size; + struct nlist *syms; + char *strings; + aout_symbol_type *cached; + + /* If there's no work to be done, don't do any */ + if (obj_aout_symbols (abfd) != (aout_symbol_type *)NULL) return true; + symbol_size = exec_hdr(abfd)->a_syms; + if (symbol_size == 0) { + bfd_error = no_symbols; + return false; + } + + bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET); + if (bfd_read ((void *)&string_size, 4, 1, abfd) != 4) + return false; + string_size = bfd_h_getlong (abfd, (unsigned char *)&string_size); + + symbol_count = symbol_size / sizeof (struct nlist); + + /* Malloc (should alloca) space for native symbols, and + malloc space for string table and symbol cache. */ + + syms = (struct nlist *) zalloc (symbol_size); + if (syms == NULL) { + bfd_error = no_memory; + return false; + } + + cached = (aout_symbol_type *) zalloc ((size_t)(string_size + 1 + + (symbol_count * sizeof (aout_symbol_type)))); + if (cached == NULL) { + bfd_error = no_memory; + free ((void *)syms); + return false; + } + + strings = ((char *) cached) + (symbol_count * sizeof (aout_symbol_type)); + + bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET); + if (bfd_read ((void *)syms, 1, symbol_size, abfd) != symbol_size) { + bailout: + free ((void *)cached); + free ((void*)syms); + return false; + } + + bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET); + if (bfd_read ((void *)strings, 1, string_size, abfd) != string_size) { + goto bailout; + } + + /* OK, now walk the new symtable, cacheing symbol properties */ + { + register struct nlist *sym_pointer; + register struct nlist *sym_end = syms + symbol_count; + register aout_symbol_type *cache_ptr = cached; + + if (bfd_header_twiddle_required (abfd) == true) { + /* run through the table and byte swap if needed */ + for (sym_pointer = syms; sym_pointer < sym_end; sym_pointer++) { + sym_pointer->n_un.n_strx = + bfd_h_get_x (abfd, &sym_pointer->n_un.n_strx); + sym_pointer->n_desc = + bfd_h_get_x (abfd, &sym_pointer->n_desc); + sym_pointer->n_value = + bfd_h_get_x (abfd, &sym_pointer->n_value); + sym_pointer->n_other = (char) + bfd_h_get_x(abfd, &sym_pointer->n_other); + sym_pointer->n_type = (char) + bfd_h_get_x(abfd, &sym_pointer->n_type); + + } + } + /* Run through table and copy values */ + for (sym_pointer = syms, cache_ptr = cached; + sym_pointer < sym_end; sym_pointer++, cache_ptr++) + { + cache_ptr->symbol.the_bfd = abfd; + if (sym_pointer->n_un.n_strx) + cache_ptr->symbol.name = sym_pointer->n_un.n_strx + strings; + else + cache_ptr->symbol.name = (char *)NULL; + cache_ptr->symbol.value = sym_pointer->n_value; + cache_ptr->desc = sym_pointer->n_desc; + cache_ptr->other = sym_pointer->n_other; + cache_ptr->type = sym_pointer->n_type; + cache_ptr->symbol.udata = 0; + translate_from_native_sym_flags (sym_pointer, cache_ptr, abfd); + + } + } + + obj_aout_symbols (abfd) = cached; + bfd_get_symcount (abfd) = symbol_count; + free ((void *)syms); + + return true; +} + + +void +sunos4_write_syms (abfd) + bfd *abfd; +{ + unsigned int count ; + asymbol **generic = bfd_get_outsymbols (abfd); + + unsigned int stindex = sizeof(stindex); /* initial string length */ + + for (count = 0; count < bfd_get_symcount (abfd); count++) { + asymbol *g = generic[count]; + struct nlist nsp; + + if (g->name) { + unsigned int length = strlen(g->name) +1; + bfd_h_putlong (abfd, stindex, (unsigned char *)&nsp.n_un.n_strx); + stindex += length; + } + else { + bfd_h_putlong (abfd, 0, (unsigned char *)&nsp.n_un.n_strx); + } + + if (g->the_bfd->xvec->flavour == abfd->xvec->flavour) + { + nsp.n_desc = aout_symbol( g)->desc; + nsp.n_other = aout_symbol(g)->other; + nsp.n_type = aout_symbol(g)->type; + } + else + { + nsp.n_desc = 0; + nsp.n_other = 0; + nsp.n_type = 0; + } + + + nsp.n_value = g->value; + translate_to_native_sym_flags (&nsp, (generic_symbol_type *)g, abfd); + + + bfd_h_putshort (abfd, nsp.n_desc, (unsigned char *)&nsp.n_desc); + bfd_h_putlong (abfd, nsp.n_value, (unsigned char *)&nsp.n_value); + bfd_write((void *)&nsp,1, sizeof(nsp), abfd); + } + + + /* Now output the strings. Be sure to put string length into correct + * byte ordering before writing it. + */ + bfd_h_putlong (abfd, stindex, (unsigned char *)&stindex); + + bfd_write((void *)&stindex, 1, sizeof(stindex), abfd); + + generic = bfd_get_outsymbols(abfd); + for (count = 0; count < bfd_get_symcount(abfd); count++) + { + asymbol *g = *(generic++); + + if (g->name != (char *)NULL) + { + size_t length = strlen(g->name)+1; + bfd_write((void *)g->name, 1, length, abfd); + } + if ((g->flags & BSF_FAKE)==0) { + g->name = itos(count); /* smash the generic symbol */ + } + } +} + + +void +sunos4_reclaim_symbol_table (abfd) + bfd *abfd; +{ + asection *section; + + if (!bfd_get_symcount (abfd)) return; + + for (section = abfd->sections; + section != (asection *) NULL; + section = section->next) + if (section->relocation) { + free ((void *)section->relocation); + section->relocation = NULL; + section->reloc_count = 0; + } + + bfd_get_symcount (abfd) = 0; + free ((void *)obj_aout_symbols (abfd)); + obj_aout_symbols (abfd) = (aout_symbol_type *)NULL; +} + +unsigned int +sunos4_get_symtab_upper_bound (abfd) + bfd *abfd; +{ + if (!sunos4_slurp_symbol_table (abfd)) return 0; + + return (bfd_get_symcount (abfd)+1) * (sizeof (aout_symbol_type *)); +} + +unsigned int +sunos4_get_symtab (abfd, location) + bfd *abfd; + asymbol **location; +{ + unsigned int counter = 0; + aout_symbol_type *symbase; + + if (!sunos4_slurp_symbol_table (abfd)) return 0; + + for (symbase = obj_aout_symbols(abfd); counter++ < bfd_get_symcount (abfd);) + *(location++) = (asymbol *)( symbase++); + *location++ =0; + return bfd_get_symcount(abfd); +} + + +/* Obsolete procedural interface; better to look at the cache directly */ + +/* User should have checked the file flags; perhaps we should return + BFD_NO_MORE_SYMBOLS if there are none? */ + +int +sunos4_get_symcount_upper_bound (abfd) + bfd *abfd; +{ + /* In case we're doing an output file or something...? */ + if (bfd_get_symcount (abfd)) return bfd_get_symcount (abfd); + + return (exec_hdr (abfd)->a_syms) / (sizeof (struct nlist)); +} + +symindex +sunos4_get_first_symbol (ignore_abfd) + bfd * ignore_abfd; +{ + return 0; +} + +symindex +sunos4_get_next_symbol (abfd, oidx) + bfd *abfd; + symindex oidx; +{ + if (oidx == BFD_NO_MORE_SYMBOLS) return BFD_NO_MORE_SYMBOLS; + return ++oidx >= bfd_get_symcount (abfd) ? BFD_NO_MORE_SYMBOLS : oidx; +} + +char * +sunos4_symbol_name (abfd, idx) + bfd *abfd; + symindex idx; +{ + return (obj_aout_symbols (abfd) + idx)->symbol.name; +} + +long +sunos4_symbol_value (abfd, idx) + bfd *abfd; + symindex idx; +{ + return (obj_aout_symbols (abfd) + idx)->symbol.value; +} + +symclass +sunos4_classify_symbol (abfd, idx) + bfd *abfd; + symindex idx; +{ + aout_symbol_type *sym = obj_aout_symbols (abfd) + idx; + + if ((sym->symbol.flags & BSF_FORT_COMM) != 0) return bfd_symclass_fcommon; + if ((sym->symbol.flags & BSF_GLOBAL) != 0) return bfd_symclass_global; + if ((sym->symbol.flags & BSF_DEBUGGING) != 0) return bfd_symclass_debugger; + if ((sym->symbol.flags & BSF_UNDEFINED) != 0) return bfd_symclass_undefined; + + return bfd_symclass_unknown; +} + +boolean +sunos4_symbol_hasclass (abfd, idx, class) + bfd *abfd; + symindex idx; + symclass class; +{ + aout_symbol_type *sym = obj_aout_symbols (abfd) + idx; + switch (class) { + case bfd_symclass_fcommon: + return (sym->symbol.flags & BSF_FORT_COMM) ? true :false; + case bfd_symclass_global: + return (sym->symbol.flags & BSF_GLOBAL) ? true:false; + case bfd_symclass_debugger: + return (sym->symbol.flags & BSF_DEBUGGING) ? true:false;; + case bfd_symclass_undefined: + return (sym->symbol.flags & BSF_UNDEFINED) ? true:false;; + default: return false; + } +} + +/** Some reloc hackery */ + + +boolean +sunos4_slurp_reloc_table (abfd, asect, symbols) + bfd *abfd; + sec_ptr asect; + asymbol **symbols; +{ + unsigned int count; + size_t reloc_size; + struct reloc_info_extended *relocs; + arelent *reloc_cache; + + 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_error = invalid_operation; + return false; + + doit: + bfd_seek (abfd, asect->rel_filepos, SEEK_SET); + count = reloc_size / sizeof (struct reloc_info_extended); + + relocs = (struct reloc_info_extended *) malloc (reloc_size); + if (!relocs) { + bfd_error = no_memory; + return false; + } + reloc_cache = (arelent *) zalloc ((size_t)(count * sizeof (arelent))); + if (reloc_cache == (arelent *)NULL) { + free ((void *)relocs); + bfd_error = no_memory; + return false; + } + + if (bfd_read ((void*) relocs, 1, reloc_size, abfd) != reloc_size) { + bfd_error = system_call_error; + free (reloc_cache); + free (relocs); + return false; + } + + { + register struct reloc_info_extended *rptr = relocs; + unsigned int counter = 0; + arelent *cache_ptr = reloc_cache; + + for (; counter < count; counter++, rptr++, cache_ptr++) { + /* john's old swap_reloc was a hell of a lot hairier... */ + /* FIXME, it needs to be!!! */ + rptr->r_address = bfd_h_getlong (abfd, &rptr->r_address); + /* FIXME NOW! + * The following can't be done because r_index is a bit field: + * + * rptr->r_index = bfd_h_getlong (abfd, &rptr->r_index); + */ + rptr->r_addend = bfd_h_getlong (abfd, &rptr->r_addend); + if (rptr->r_extern) { + /* If this bit is set then the r_index is a index into the symbol table + * if the bit is not set then r_index contains a section map. + * We either fill in the sym entry with a pointer to the symbol, + * or point to the correct section + */ + + cache_ptr->sym_ptr_ptr = symbols + rptr->r_index; + cache_ptr->addend = rptr->r_addend; + cache_ptr->section = (asection *)NULL; + } + else + { + /* Remember that in a.out symbols are relative to the + beginning of the file rather than sections ? (look in + translate_from_native_sym_flags) The reloc entry addend + has added to it the offset into the file of the data, so + subtract the base to make the reloc section relative */ + + cache_ptr->sym_ptr_ptr = (asymbol **)NULL; + switch (rptr->r_index) { + case N_TEXT: + case N_TEXT | N_EXT: + cache_ptr->section = obj_textsec(abfd); + cache_ptr->addend = rptr->r_addend - obj_textsec(abfd)->vma ; + break; + case N_DATA: + case N_DATA | N_EXT: + cache_ptr->section = obj_datasec(abfd); + cache_ptr->addend = rptr->r_addend - obj_datasec(abfd)->vma ; + break; + case N_BSS: + case N_BSS | N_EXT: + cache_ptr->section = obj_bsssec(abfd); + cache_ptr->addend = rptr->r_addend - obj_bsssec(abfd)->vma; + break; + case N_ABS: + case N_ABS | N_EXT: + BFD_ASSERT(1); + break; + default: + BFD_ASSERT(1); + break; + } + + } + + cache_ptr->address = rptr->r_address; + cache_ptr->howto = howto_table + (unsigned int)( rptr->r_type); + } + } + + free (relocs); + asect->relocation = reloc_cache; + asect->reloc_count = count; + return true; +} + +static boolean +sunos4_squirt_out_relocs (abfd, section) + bfd *abfd; + asection *section; +{ + arelent **generic; + + unsigned int count = section->reloc_count; + struct reloc_info_extended *native, *natptr; + size_t natsize = count * sizeof (struct reloc_info_extended); + + if (count == 0) return true; + generic = section->orelocation; + native = ((struct reloc_info_extended *) zalloc (natsize)); + if (!native) { + bfd_error = no_memory; + return false; + } + + for (natptr = native; count != 0; --count, ++natptr, ++generic) + { + arelent *g = *generic; + + natptr->r_address = g->address; + /* Find a type in the output format which matches the input howto - + * at the moment we assume input format == output format FIXME!! + */ + natptr->r_type = (enum reloc_type) g->howto->type; + /* name clobbered by sunos4_write_syms to be symbol index*/ + + if (g->sym_ptr_ptr != (asymbol **)NULL) + { + if ((*(g->sym_ptr_ptr))->section) { + /* replace the section offset into the addent */ + g->addend += (*(g->sym_ptr_ptr))->section->vma; + } + + natptr->r_index = stoi((*(g->sym_ptr_ptr))->name); + BFD_ASSERT(natptr->r_index < 0xfff); + natptr->r_extern = 1; + natptr->r_addend = g->addend; + } + else { + natptr->r_extern = 0; + if (g->section == (asection *)NULL) { + BFD_ASSERT(0); + natptr->r_index = N_ABS | N_EXT; + natptr->r_addend = g->addend; + } + else if(g->section->output_section == obj_textsec(abfd)) { + natptr->r_index = N_TEXT | N_EXT; + natptr->r_addend = g->addend + obj_textsec(abfd)->vma; + } + else if (g->section->output_section == obj_datasec(abfd)) { + natptr->r_index = N_DATA | N_EXT; + natptr->r_addend = g->addend + obj_datasec(abfd)->vma; + } + else if (g->section->output_section == obj_bsssec(abfd)) { + natptr->r_index = N_BSS | N_EXT ; + natptr->r_addend = g->addend + obj_bsssec(abfd)->vma; + + } + else { + BFD_ASSERT(0); + } + } + + if ( bfd_header_twiddle_required(abfd) ){ + bfd_h_putlong ( abfd, natptr->r_address, &natptr->r_address ); + + /* FIXME -- NOW! + * + * I came through here as part of my campaign to make compile-time + * definition of host and target byte orders unnecessary. The new + * code won't even compile because but r_index is a bit field. + * But the simple-minded byte swap that was here before wasn't going + * to work on a bit field anyway. + * + * The old code used to be #ifdef'd on + * TARGET_BYTE_ORDER_BIG_P != HOST_BYTE_ORDER_BIG_P + * Apparently, it was never tested in such a condition: the + * macro invocations here (of swapoutlong) had the wrong number + * of arguments and would never have compiled. + * Chris + bfd_h_putlong ( abfd, natptr->r_index, &natptr->r_index ); + */ + + bfd_h_putlong ( abfd, natptr->r_addend, &natptr->r_addend ); + } + + } + + if ( bfd_write ((void *) native, 1, natsize, abfd) != natsize) { + free(native); + return false; + } + free (native); + + return true; +} + +/* This is stupid. This function should be a boolean predicate */ +unsigned int +sunos4_canonicalize_reloc (abfd, section, relptr, symbols) + bfd *abfd; + sec_ptr section; + arelent **relptr; + asymbol **symbols; +{ + arelent *tblptr = section->relocation; + unsigned int count; + + if (!(tblptr || sunos4_slurp_reloc_table (abfd, section, symbols))) + return 0; + + 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; + if (!tblptr) return 0; + + for (count = 0; count++ < section->reloc_count;) + { + *relptr++ = tblptr++; + } + } + *relptr = 0; + + return section->reloc_count; +} + +unsigned int +sunos4_get_reloc_upper_bound (abfd, asect) + bfd *abfd; + sec_ptr asect; +{ + if (bfd_get_format (abfd) != bfd_object) { + bfd_error = invalid_operation; + return 0; + } + if (asect->flags & SEC_CONSTRUCTOR) { + return (sizeof (arelent *) * (asect->reloc_count+1)); + } + + if (asect == obj_datasec (abfd)) + return (sizeof (arelent *) * + ((exec_hdr(abfd)->a_drsize / sizeof (struct reloc_info_extended)) + +1)); + + if (asect == obj_textsec (abfd)) + return (sizeof (arelent *) * + ((exec_hdr(abfd)->a_trsize / sizeof (struct reloc_info_extended)) + +1)); + + bfd_error = invalid_operation; + return 0; +} + +void +sunos4_reclaim_reloc (ignore_abfd, section) + bfd *ignore_abfd; + sec_ptr section; +{ + if (section->relocation) { + free (section->relocation); + section->relocation = NULL; + section->reloc_count = 0; + } +} + + +alent * +sunos4_get_lineno(ignore_abfd, ignore_symbol) +bfd *ignore_abfd; +generic_symbol_type *ignore_symbol; +{ +return (alent *)NULL; +} + +void +sunos4_print_symbol(ignore_abfd, file, symbol, how) +bfd *ignore_abfd; +FILE *file; +asymbol *symbol; +bfd_print_symbol_enum_type how; +{ + switch (how) { + case bfd_print_symbol_name_enum: + fprintf(file,"%s", symbol->name); + break; + case bfd_print_symbol_type_enum: + fprintf(file,"%4x %2x %2x",(unsigned)(aout_symbol(symbol)->desc & 0xffff), + (unsigned)( aout_symbol(symbol)->other & 0xff), + (unsigned)(aout_symbol(symbol)->type)); + break; + case bfd_print_symbol_all_enum: + { + char *section_name = symbol->section == (asection *)NULL ? + "*abs" : symbol->section->name; + + bfd_print_symbol_vandf((void *)file,symbol); + + fprintf(file," %-5s %04x %02x %02x %s", + section_name, + (unsigned)(aout_symbol(symbol)->desc & 0xffff), + (unsigned)(aout_symbol(symbol)->other & 0xff), + (unsigned)(aout_symbol(symbol)->type & 0xff), + symbol->name); + } + break; + } +} +/* Once we know all the stuff that could be consed, we know how to clean + it up. So why don't we? */ + +boolean +sunos4_close_and_cleanup (abfd) + bfd *abfd; +{ + if (!bfd_read_p (abfd)) + switch (abfd->format) { + case bfd_archive: + if (!_bfd_write_archive_contents (abfd)) return false; break; + case bfd_object: + if (!sunos4_write_object_contents (abfd)) return false; break; + default: bfd_error = invalid_operation; return false; + } + +#define cleaner(ptr) if (abfd->ptr) free (abfd->ptr) + cleaner (tdata); + + if (abfd->my_archive) + cleaner (filename); + +#undef cleaner + return true; +} + +/* + provided a bfd, a section and an offset into the section, calculate + and return the name of the source file and the line nearest to the + wanted location. +*/ + +boolean +sunos4_find_nearest_line(abfd, + section, + symbols, + offset, + filename_ptr, + functionname_ptr, + line_ptr) +bfd *abfd; +asection *section; +asymbol **symbols; +bfd_vma offset; +char **filename_ptr; +char **functionname_ptr; +unsigned int *line_ptr; +{ + /* Run down the file looking for the filename, function and linenumber */ + asymbol **p; + static char buffer[100]; + bfd_vma high_line_vma = ~0; + bfd_vma low_func_vma = 0; + asymbol *func = 0; + *filename_ptr = abfd->filename; + *functionname_ptr = 0; + *line_ptr = 0; + if (symbols != (asymbol **)NULL) { + for (p = symbols; *p; p++) { + aout_symbol_type *q = (aout_symbol_type *)(*p); + switch (q->type){ + case N_SO: + *filename_ptr = q->symbol.name; + if (obj_textsec(abfd) != section) { + return true; + } + break; + case N_SLINE: + + case N_DSLINE: + case N_BSLINE: + /* We'll keep this if it resolves nearer than the one we have already */ + if (q->symbol.value >= offset && + q->symbol.value < high_line_vma) { + *line_ptr = q->desc; + high_line_vma = q->symbol.value; + } + break; + case N_FUN: + { + /* We'll keep this if it is nearer than the one we have already */ + if (q->symbol.value >= low_func_vma && + q->symbol.value <= offset) { + low_func_vma = q->symbol.value; + func = (asymbol *)q; + } + if (*line_ptr && func) { + char *function = func->name; + char *p; + strncpy(buffer, function, sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = 0; + /* Have to remove : stuff */ + p = strchr(buffer,':'); + if (p != NULL) {*p = NULL; } + *functionname_ptr = buffer; + return true; + + } + } + break; + } + } + } + + return true; + +} + +bfd_target aoutvec = +{ + "a.out-generic-big", /* name */ + bfd_target_aout_flavour_enum, + true, /* target byte order */ + true, /* target headers byte order */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED), + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* valid reloc types */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + sunos4_close_and_cleanup, /* _close_and_cleanup */ + sunos4_set_section_contents, /* bfd_set_section_contents */ + sunos4_get_section_contents, /* bfd_get_section_contents */ + sunos4_new_section_hook, /* new_section_hook */ + sunos4_core_file_failing_command, /* _core_file_failing_command */ + sunos4_core_file_failing_signal, /* _core_file_failing_signal */ + sunos4_core_file_matches_executable_p, /* _core_file_matches_ex...p */ + + bfd_slurp_bsd_armap, /* bfd_slurp_armap */ + bfd_true, /* bfd_slurp_extended_name_table */ + bfd_bsd_truncate_arname, /* bfd_truncate_arname */ + + sunos4_get_symtab_upper_bound, /* get_symtab_upper_bound */ + sunos4_get_symtab, /* canonicalize_symtab */ + sunos4_reclaim_symbol_table, /* bfd_reclaim_symbol_table */ + sunos4_get_reloc_upper_bound, /* get_reloc_upper_bound */ + sunos4_canonicalize_reloc, /* bfd_canonicalize_reloc */ + sunos4_reclaim_reloc, /* bfd_reclaim_reloc */ + sunos4_get_symcount_upper_bound, /* bfd_get_symcount_upper_bound */ + sunos4_get_first_symbol, /* bfd_get_first_symbol */ + sunos4_get_next_symbol, /* bfd_get_next_symbol */ + sunos4_classify_symbol, /* bfd_classify_symbol */ + sunos4_symbol_hasclass, /* bfd_symbol_hasclass */ + sunos4_symbol_name, /* bfd_symbol_name */ + sunos4_symbol_value, /* bfd_symbol_value */ + + _do_getblong, _do_putblong, _do_getbshort, _do_putbshort, /* data */ + _do_getblong, _do_putblong, _do_getbshort, _do_putbshort, /* hdrs */ + + {_bfd_dummy_target, sunos4_object_p, /* bfd_check_format */ + bfd_generic_archive_p, sunos4_core_file_p}, + {bfd_false, sunos4_mkobject, /* bfd_zxset_format */ + _bfd_generic_mkarchive, bfd_false}, + sunos4_make_empty_symbol, + sunos4_print_symbol, + sunos4_get_lineno, + sunos4_set_arch_mach, + bsd_write_armap, + bfd_generic_openr_next_archived_file, + sunos4_find_nearest_line, /* bfd_find_nearest_line */ + bfd_generic_stat_arch_elt /* bfd_stat_arch_elt */ + }; + diff --git a/bfd/targets.c b/bfd/targets.c new file mode 100644 index 00000000000..77fabb61f4c --- /dev/null +++ b/bfd/targets.c @@ -0,0 +1,50 @@ +/* Copyright (C) 1990, 1991 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Diddler. + +BFD 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 1, or (at your option) +any later version. + +BFD 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 BFD; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* $Id$ */ + + +/* This -*- C -*- source file will someday be machine-generated */ + +/*** Defines the target vector through which operations dispatch */ +#include "sysdep.h" +#include "bfd.h" +#include "libbfd.h" + +extern bfd_target aoutvec; +extern bfd_target srec_vec; +extern bfd_target b_out_vec_little_host; +extern bfd_target b_out_vec_big_host; +extern bfd_target icoff_little_vec; +extern bfd_target icoff_big_vec; + + +bfd_target *target_vector[] = + { +#ifndef INTEL960VERSION + &aoutvec, + &srec_vec, + +#endif /* INTEL960VERSION */ + &icoff_big_vec, + &icoff_little_vec, + &b_out_vec_big_host, + &b_out_vec_little_host, + + NULL + }; -- 2.30.2