aboutsummaryrefslogtreecommitdiff
path: root/binutils-1.9/hp-bin/hpxt.c
diff options
context:
space:
mode:
Diffstat (limited to 'binutils-1.9/hp-bin/hpxt.c')
-rw-r--r--binutils-1.9/hp-bin/hpxt.c1077
1 files changed, 1077 insertions, 0 deletions
diff --git a/binutils-1.9/hp-bin/hpxt.c b/binutils-1.9/hp-bin/hpxt.c
new file mode 100644
index 0000000..a07188a
--- /dev/null
+++ b/binutils-1.9/hp-bin/hpxt.c
@@ -0,0 +1,1077 @@
+/* Program to translate binary format files from HP-UX to GNU.
+ Input formats for HP 9000 series 300/400 only.
+ Copyright (C) 1988 Free Software Foundation, Inc.
+
+ 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. */
+
+#if !defined(hp9000s300) && !defined(__hp9000s300)
+#include "error: hpxt is for 300- or 400-series machines only"
+#endif
+
+#include <stdio.h>
+#include <varargs.h>
+#include <fcntl.h>
+#include <sys/file.h>
+#include <string.h>
+#define index(s, c) strchr (s, c)
+#define bzero(p, n) memset (p, 0, n)
+#include "ioutil.h"
+
+#define forward extern
+
+/* IO primitives */
+
+void
+xread (input_file, buffer, length)
+ int input_file;
+ char *buffer;
+ int length;
+{
+ if ((iou_read (input_file, buffer, length)) != length)
+ iou_error ("read failed to complete");
+ return;
+}
+
+/* HP-UX data structure descriptions */
+
+struct hp_magic
+ {
+ unsigned short system_id;
+ unsigned short file_type;
+ };
+
+#define HP_SYSID_98x6 0x020A
+#define HP_SYSID_9000S200 0x020C
+
+#define HP_SYSID_OK(sysid) \
+ (((sysid) == HP_SYSID_9000S200) \
+ || ((sysid) == HP_SYSID_98x6))
+
+#define HP_FILETYPE_RELOC 0x0106 /* relocatable only */
+#define HP_FILETYPE_EXEC 0x0107 /* normal executable */
+#define HP_FILETYPE_SHARE 0x0108 /* shared executable */
+#define HP_FILETYPE_DEMAND 0x010B /* demand-load executable */
+
+#define HP_FILETYPE_OK(filetype) \
+ (((filetype) == HP_FILETYPE_EXEC) \
+ || ((filetype) == HP_FILETYPE_SHARE) \
+ || ((filetype) == HP_FILETYPE_DEMAND) \
+ || ((filetype) == HP_FILETYPE_RELOC))
+
+#define HP_MAGIC_OK(magic) \
+ ((HP_SYSID_OK ((magic) . system_id)) \
+ && (HP_FILETYPE_OK ((magic) . file_type)))
+
+struct hp_exec
+ {
+ struct hp_magic a_magic;
+ short a_stamp; /* version id */
+ short a_unused;
+ long a_sparehp;
+ long a_text; /* size of text segment */
+ long a_data; /* size of data segment */
+ long a_bss; /* size of bss segment */
+ long a_trsize; /* text relocation size */
+ long a_drsize; /* data relocation size */
+ long a_pasint; /* pascal interface size */
+ long a_lesyms; /* symbol table size */
+ long a_dnttsize; /* debug name table size */
+ long a_entry; /* entry point */
+ long a_sltsize; /* source line table size */
+ long a_vtsize; /* value table size */
+ long a_spare3;
+ long a_spare4;
+ };
+
+#define HP_EXEC_MAGIC(header) (((header) . a_magic) . file_type)
+
+#define HP_PAGE_SIZE 0x1000
+
+#define HP_PAGE_SEEK(descriptor, header, offset) \
+{ \
+ if ((HP_EXEC_MAGIC (header)) == HP_FILETYPE_DEMAND) \
+ { \
+ int HP_PAGE_SEEK_remainder; \
+ \
+ HP_PAGE_SEEK_remainder = ((offset) % HP_PAGE_SIZE); \
+ if (HP_PAGE_SEEK_remainder != 0) \
+ iou_lseek \
+ ((descriptor), (HP_PAGE_SIZE - HP_PAGE_SEEK_remainder), 1); \
+ } \
+}
+
+struct hp_nlist
+ {
+ long n_value;
+ unsigned char n_type;
+ unsigned char n_length; /* length of ascii symbol name */
+ short n_almod; /* alignment mod */
+ short n_unused;
+ };
+
+#define HP_SYMTYPE_UNDEFINED 0x00
+#define HP_SYMTYPE_ABSOLUTE 0x01
+#define HP_SYMTYPE_TEXT 0x02
+#define HP_SYMTYPE_DATA 0x03
+#define HP_SYMTYPE_BSS 0x04
+#define HP_SYMTYPE_COMMON 0x05
+#define HP_SYMTYPE_FILENAME 0x1F
+
+#define HP_SYMTYPE_ALIGN 0x10
+#define HP_SYMTYPE_EXTERNAL 0x20
+
+#define HP_SYMTYPE_TYPE 0x0F
+
+struct hp_relocation_info
+ {
+ long r_address; /* position of relocation in segment */
+ short r_symbolnum; /* id of the symbol of external relocations */
+ char r_segment;
+ char r_length;
+ };
+
+#define HP_RSEGMENT_TEXT 0x00
+#define HP_RSEGMENT_DATA 0x01
+#define HP_RSEGMENT_BSS 0x02
+#define HP_RSEGMENT_EXTERNAL 0x03
+#define HP_RSEGMENT_NOOP 0x3F
+
+#define HP_RLENGTH_BYTE 0x00
+#define HP_RLENGTH_WORD 0x01
+#define HP_RLENGTH_LONG 0x02
+#define HP_RLENGTH_ALIGN 0x03
+
+#define HP_ARMAG "!<arch>\n"
+#define HP_SARMAG 8
+#define HP_ARFMAG "`\n"
+
+struct hp_ar_hdr
+ {
+ char ar_name [16]; /* file member name - `/' terminated */
+ char ar_date [12]; /* file member date - decimal */
+ char ar_uid [6]; /* file member user id - decimal */
+ char ar_gid [6]; /* file member group id - decimal */
+ char ar_mode [8]; /* file member mode - octal */
+ char ar_size [10]; /* file member size - decimal */
+ char ar_fmag [2]; /* ARFMAG - string to end header */
+ };
+
+struct hp_ar_symtab_hdr
+ {
+ unsigned short n_entries;
+ long string_table_size;
+ };
+
+struct hp_ar_symtab_entry
+ {
+ long string_index;
+ long file_index;
+ };
+
+/* GNU data structure descriptions */
+
+#ifdef hpux
+
+/* The `exec' structure and overall layout must be close to HP's when
+ we are running on an HP system, otherwise we will not be able to
+ execute the resulting file. */
+
+#define GNU_OMAGIC HP_FILETYPE_EXEC
+#define GNU_NMAGIC HP_FILETYPE_SHARE
+#define GNU_ZMAGIC HP_FILETYPE_SHARE
+
+struct gnu_exec
+ {
+ struct hp_magic a_magic;
+ unsigned long a_spare1;
+ unsigned long a_spare2;
+ unsigned long a_text; /* size of text segment */
+ unsigned long a_data; /* size of data segment */
+ unsigned long a_bss; /* size of bss segment */
+ unsigned long a_trsize; /* text relocation size */
+ unsigned long a_drsize; /* data relocation size */
+ unsigned long a_spare3; /* HP = pascal interface size */
+ unsigned long a_spare4; /* HP = symbol table size */
+ unsigned long a_spare5; /* HP = debug name table size */
+ unsigned long a_entry; /* entry point */
+ unsigned long a_spare6; /* HP = source line table size */
+ unsigned long a_spare7; /* HP = value table size */
+ unsigned long a_syms; /* symbol table size */
+ unsigned long a_spare8;
+ };
+
+#define GNU_EXEC_MAGIC(header) (((header) . a_magic) . file_type)
+
+#define GNU_EXEC_SET_MAGIC(header, magic) \
+{ \
+ (((header) . a_magic) . system_id) = HP_SYSID_9000S200; \
+ (((header) . a_magic) . file_type) = (magic); \
+}
+
+#define GNU_PAGE_SEEK_HEADER HP_PAGE_SEEK
+#define GNU_PAGE_SEEK_TEXT HP_PAGE_SEEK
+
+#else /* not hpux */
+
+#define GNU_OMAGIC 0407 /* old impure format */
+#define GNU_NMAGIC 0410 /* read-only text */
+#define GNU_ZMAGIC 0413 /* demand load format */
+
+struct gnu_exec
+ {
+ unsigned long a_magic; /* magic number */
+ unsigned long a_text; /* size of text segment */
+ unsigned long a_data; /* size of initialized data */
+ unsigned long a_bss; /* size of uninitialized data */
+ unsigned long a_syms; /* size of symbol table */
+ unsigned long a_entry; /* entry point */
+ unsigned long a_trsize; /* size of text relocation */
+ unsigned long a_drsize; /* size of data relocation */
+ };
+
+#define GNU_EXEC_MAGIC(header) ((header) . a_magic)
+#define GNU_EXEC_SET_MAGIC(header, magic) ((header) . a_magic) = (magic)
+
+#define GNU_PAGE_SIZE 0x400
+
+#define GNU_PAGE_SEEK_HEADER(descriptor, header, offset) \
+{ \
+ if ((GNU_EXEC_MAGIC (header)) == GNU_ZMAGIC) \
+ { \
+ int GNU_PAGE_SEEK_remainder; \
+ \
+ GNU_PAGE_SEEK_remainder = ((offset) % GNU_PAGE_SIZE); \
+ if (GNU_PAGE_SEEK_remainder != 0) \
+ iou_lseek \
+ ((descriptor), (GNU_PAGE_SIZE - GNU_PAGE_SEEK_remainder), 1); \
+ } \
+}
+
+#define GNU_PAGE_SEEK_TEXT(descriptor, header, offset)
+
+#endif /* hpux */
+
+struct gnu_nlist
+ {
+ union
+ {
+ char *n_name; /* for use when in-core */
+ long n_strx; /* index into file string table */
+ } n_un;
+ unsigned char n_type; /* type flag (N_TEXT,..) */
+ char n_other; /* unused */
+ short n_desc; /* see <stab.h> */
+ unsigned long n_value; /* value of symbol (or sdb offset) */
+ };
+
+#define GNU_SYMTYPE_UNDEFINED 0x0
+#define GNU_SYMTYPE_ABSOLUTE 0x2
+#define GNU_SYMTYPE_TEXT 0x4
+#define GNU_SYMTYPE_DATA 0x6
+#define GNU_SYMTYPE_BSS 0x8
+#define GNU_SYMTYPE_COMMON 0x12
+#define GNU_SYMTYPE_FILENAME 0x1F
+#define GNU_SYMTYPE_EXTERNAL 0x01
+
+struct gnu_relocation_info
+ {
+ long r_address; /* address which is relocated */
+ unsigned int
+ r_symbolnum : 24, /* local symbol ordinal */
+ r_pcrel : 1, /* was relocated pc relative already */
+ r_length : 2, /* BYTE, WORD, or LONG */
+ r_extern : 1, /* does not include value of sym referenced */
+ : 4; /* nothing, yet */
+ };
+
+#define GNU_RLENGTH_BYTE 0x00
+#define GNU_RLENGTH_WORD 0x01
+#define GNU_RLENGTH_LONG 0x02
+
+#define GNU_ARMAG "!<arch>\n"
+#define GNU_SARMAG 8
+#define GNU_ARFMAG "`\n"
+
+struct gnu_ar_hdr
+ {
+ char ar_name [16];
+ char ar_date [12];
+ char ar_uid [6];
+ char ar_gid [6];
+ char ar_mode [8];
+ char ar_size [10];
+ char ar_fmag [2];
+ };
+
+struct gnu_symdef
+ {
+ int symbol_name_string_index;
+ int library_member_offset;
+ };
+
+/* List abstraction */
+
+struct pair
+ {
+ char *car;
+ char *cdr;
+ };
+
+struct pair *
+pair_cons (car, cdr)
+ char *car;
+ char *cdr;
+{
+ register struct pair *result;
+
+ result = ((struct pair *) (iou_malloc (sizeof (struct pair))));
+ (result -> car) = car;
+ (result -> cdr) = cdr;
+ return (result);
+}
+
+#define LIST_CDR(list) ((struct pair *) ((list) -> cdr))
+#define LIST_SET_CDR(list, newcdr) (list -> cdr) = ((char *) newcdr)
+
+struct pair *
+list_reverse (list)
+ register struct pair *list;
+{
+ register struct pair *previous;
+ register struct pair *next;
+
+ previous = NULL;
+ while (list != NULL)
+ {
+ next = (LIST_CDR (list));
+ LIST_SET_CDR (list, previous);
+ previous = list;
+ list = next;
+ }
+ return (previous);
+}
+
+struct pair *
+read_list (input_file, n_bytes, field_name, read_item, length)
+ int input_file;
+ int n_bytes;
+ char * field_name;
+ char * (* read_item) ();
+ register int * length; /* return value */
+{
+ register struct pair *result;
+
+ result = NULL;
+ (* length) = 0;
+ while (n_bytes > 0)
+ {
+ result = (pair_cons (((* read_item) (input_file, (& n_bytes))), result));
+ (* length) += 1;
+ }
+ if (n_bytes != 0)
+ iou_error ("%s field size incorrect", field_name);
+ return (list_reverse (result));
+}
+
+/* Symbol Table */
+
+struct gnu_nlist *
+read_symbol (input_file, n_bytes)
+ int input_file;
+ int *n_bytes; /* return value */
+{
+ struct hp_nlist input_nlist;
+ register struct gnu_nlist *output_nlist;
+ register char *name;
+
+ {
+ register int name_length;
+
+ xread (input_file, (& input_nlist), (sizeof (input_nlist)));
+ name_length = (input_nlist . n_length);
+ name = (iou_malloc (name_length + 1));
+ xread (input_file, name, name_length);
+ (name [name_length]) = '\0';
+ (* n_bytes) -= ((sizeof (input_nlist)) + name_length);
+ }
+
+ output_nlist =
+ ((struct gnu_nlist *) (iou_malloc (sizeof (struct gnu_nlist))));
+ ((output_nlist -> n_un) . n_name) = name;
+ (output_nlist -> n_other) = 0;
+ (output_nlist -> n_desc) = 0;
+ (output_nlist -> n_value) = (input_nlist . n_value);
+
+ {
+ register int name_type;
+
+ name_type = (input_nlist . n_type);
+ if ((name_type & HP_SYMTYPE_ALIGN) != 0)
+ iou_error ("aligned symbol encountered: %s", name);
+ if (name_type == HP_SYMTYPE_FILENAME)
+ (output_nlist -> n_type) = GNU_SYMTYPE_FILENAME;
+ else
+ {
+ switch (name_type & HP_SYMTYPE_TYPE)
+ {
+ case HP_SYMTYPE_UNDEFINED:
+ (output_nlist -> n_type) = GNU_SYMTYPE_UNDEFINED;
+ break;
+
+ case HP_SYMTYPE_ABSOLUTE:
+ (output_nlist -> n_type) = GNU_SYMTYPE_ABSOLUTE;
+ break;
+
+ case HP_SYMTYPE_TEXT:
+ (output_nlist -> n_type) = GNU_SYMTYPE_TEXT;
+ break;
+
+ case HP_SYMTYPE_DATA:
+ (output_nlist -> n_type) = GNU_SYMTYPE_DATA;
+ break;
+
+ case HP_SYMTYPE_BSS:
+ (output_nlist -> n_type) = GNU_SYMTYPE_BSS;
+ break;
+
+ case HP_SYMTYPE_COMMON:
+ (output_nlist -> n_type) = GNU_SYMTYPE_COMMON;
+ break;
+
+ default:
+ iou_error ("unknown symbol type encountered: %x", name_type);
+ }
+ if ((name_type & HP_SYMTYPE_EXTERNAL) != 0)
+ (output_nlist -> n_type) |= GNU_SYMTYPE_EXTERNAL;
+ }
+ }
+
+ return (output_nlist);
+}
+
+struct pair *
+read_symbol_table (input_file, n_bytes, length)
+ int input_file;
+ int n_bytes;
+ int * length; /* return value */
+{
+ return
+ (read_list (input_file, n_bytes, "symbol table", read_symbol, length));
+}
+
+void
+write_symbol_table (output_file, symbol_table, length)
+ int output_file;
+ struct pair *symbol_table;
+ int length;
+{
+ register struct pair *scan;
+ register char *name;
+ struct gnu_nlist output_nlist;
+ int string_table_index;
+
+ (output_nlist . n_other) = 0;
+ (output_nlist . n_desc) = 0;
+
+ string_table_index = (sizeof (string_table_index));
+ for (scan = symbol_table; (scan != NULL); scan = (LIST_CDR (scan)))
+ {
+ register struct gnu_nlist *symbol;
+
+ symbol = ((struct gnu_nlist *) (scan -> car));
+ name = ((symbol -> n_un) . n_name);
+
+ ((output_nlist . n_un) . n_strx) = string_table_index;
+ (output_nlist . n_type) = (symbol -> n_type);
+ (output_nlist . n_value) = (symbol -> n_value);
+ iou_write (output_file, (& output_nlist), (sizeof (output_nlist)));
+
+ string_table_index += ((strlen (name)) + 1);
+ (scan -> car) = name;
+ iou_free (symbol);
+ }
+ iou_write
+ (output_file, (& string_table_index), (sizeof (string_table_index)));
+
+ scan = symbol_table;
+ while (scan != NULL)
+ {
+ register struct pair *cdr;
+
+ name = (scan -> car);
+ iou_write (output_file, name, ((strlen (name)) + 1));
+ iou_free (name);
+ cdr = (LIST_CDR (scan));
+ iou_free (scan);
+ scan = cdr;
+ }
+ return;
+}
+
+/* Relocation Info */
+
+struct gnu_relocation_info *
+read_relocation_info_1 (input_file, n_bytes)
+ int input_file;
+ register int * n_bytes; /* return value */
+{
+ struct hp_relocation_info input_info;
+ register struct gnu_relocation_info *output_info;
+
+ xread (input_file, (& input_info), (sizeof (input_info)));
+ (* n_bytes) -= (sizeof (input_info));
+
+ output_info =
+ ((struct gnu_relocation_info *)
+ (iou_malloc (sizeof (struct gnu_relocation_info))));
+ (output_info -> r_pcrel) = 0;
+ (output_info -> r_address) = (input_info . r_address);
+
+ switch (input_info . r_segment)
+ {
+ case HP_RSEGMENT_TEXT:
+ (output_info -> r_symbolnum) = GNU_SYMTYPE_TEXT;
+ (output_info -> r_extern) = 0;
+ break;
+
+ case HP_RSEGMENT_DATA:
+ (output_info -> r_symbolnum) = GNU_SYMTYPE_DATA;
+ (output_info -> r_extern) = 0;
+ break;
+
+ case HP_RSEGMENT_BSS:
+ (output_info -> r_symbolnum) = GNU_SYMTYPE_BSS;
+ (output_info -> r_extern) = 0;
+ break;
+
+ case HP_RSEGMENT_EXTERNAL:
+ (output_info -> r_symbolnum) = (input_info . r_symbolnum);
+ (output_info -> r_extern) = 1;
+ break;
+
+ default:
+ iou_error
+ ("illegal relocation segment type: %x", (input_info . r_segment));
+ }
+
+ switch (input_info . r_length)
+ {
+ case HP_RLENGTH_BYTE:
+ (output_info -> r_length) = GNU_RLENGTH_BYTE;
+ break;
+
+ case HP_RLENGTH_WORD:
+ (output_info -> r_length) = GNU_RLENGTH_WORD;
+ break;
+
+ case HP_RLENGTH_LONG:
+ (output_info -> r_length) = GNU_RLENGTH_LONG;
+ break;
+
+ default:
+ iou_error ("illegal relocation length: %x", (input_info . r_length));
+ }
+
+ return (output_info);
+}
+
+struct pair *
+read_relocation_info (input_file, n_bytes, length)
+ int input_file;
+ int n_bytes;
+ int * length;
+{
+ return
+ (read_list
+ (input_file, n_bytes, "relocation info", read_relocation_info_1, length));
+}
+
+void
+write_relocation_info (output_file, relocation_info, length)
+ int output_file;
+ struct pair *relocation_info;
+ int length;
+{
+ register struct pair *this;
+ register struct gnu_relocation_info *car;
+ register struct pair *cdr;
+
+ this = relocation_info;
+ while (this != NULL)
+ {
+ car = ((struct gnu_relocation_info *) (this -> car));
+ iou_write (output_file, car, (sizeof (struct gnu_relocation_info)));
+ iou_free (car);
+ cdr = (LIST_CDR (this));
+ iou_free (this);
+ this = cdr;
+ }
+ return;
+}
+
+/* Convert an executable (or relocatable) file. */
+
+void
+process_executable_file (input_file, output_file)
+ int input_file;
+ int output_file;
+{
+ struct hp_exec input_exec;
+ struct gnu_exec output_exec;
+ char *text_segment;
+ char *data_segment;
+ struct pair *symbol_table;
+ int symbol_table_length;
+ struct pair *text_relocation_info;
+ int text_relocation_info_length;
+ struct pair *data_relocation_info;
+ int data_relocation_info_length;
+
+ xread (input_file, (& input_exec), (sizeof (input_exec)));
+ HP_PAGE_SEEK (input_file, input_exec, (sizeof (input_exec)));
+
+ if ((input_exec . a_text) != 0)
+ {
+ text_segment = (iou_malloc (input_exec . a_text));
+ xread (input_file, text_segment, (input_exec . a_text));
+ HP_PAGE_SEEK (input_file, input_exec, (input_exec . a_text));
+ }
+ else
+ text_segment = NULL;
+
+ if ((input_exec . a_data) != 0)
+ {
+ data_segment = (iou_malloc (input_exec . a_data));
+ xread (input_file, data_segment, (input_exec . a_data));
+ HP_PAGE_SEEK (input_file, input_exec, (input_exec . a_data));
+ }
+ else
+ data_segment = NULL;
+
+ /* Skip the pascal interface text */
+ iou_lseek (input_file, (input_exec . a_pasint), 1);
+
+ symbol_table =
+ (read_symbol_table
+ (input_file, (input_exec . a_lesyms), (& symbol_table_length)));
+
+ /* Skip the debugging tables */
+ iou_lseek
+ (input_file,
+ ((input_exec . a_dnttsize)
+ + (input_exec . a_sltsize)
+ + (input_exec . a_vtsize)),
+ 1);
+
+ text_relocation_info =
+ (read_relocation_info
+ (input_file, (input_exec . a_trsize), (& text_relocation_info_length)));
+ data_relocation_info =
+ (read_relocation_info
+ (input_file, (input_exec . a_drsize), (& data_relocation_info_length)));
+
+ bzero ((& output_exec), (sizeof (output_exec)));
+ switch (HP_EXEC_MAGIC (input_exec))
+ {
+ case HP_FILETYPE_RELOC:
+ case HP_FILETYPE_EXEC:
+ GNU_EXEC_SET_MAGIC (output_exec, GNU_OMAGIC);
+ break;
+
+ case HP_FILETYPE_SHARE:
+ GNU_EXEC_SET_MAGIC (output_exec, GNU_NMAGIC);
+ break;
+
+ case HP_FILETYPE_DEMAND:
+ GNU_EXEC_SET_MAGIC (output_exec, GNU_ZMAGIC);
+ break;
+
+ default:
+ iou_error ("unknown magic type: %x", (HP_EXEC_MAGIC (input_exec)));
+ }
+ (output_exec . a_text) = (input_exec . a_text);
+ (output_exec . a_data) = (input_exec . a_data);
+ (output_exec . a_bss) = (input_exec . a_bss);
+ (output_exec . a_syms) = (symbol_table_length * (sizeof (struct gnu_nlist)));
+ (output_exec . a_entry) = (input_exec . a_entry);
+ (output_exec . a_trsize) = (input_exec . a_trsize);
+ (output_exec . a_drsize) = (input_exec . a_drsize);
+
+ iou_write (output_file, (& output_exec), (sizeof (output_exec)));
+ GNU_PAGE_SEEK_HEADER (output_file, output_exec, (sizeof (output_exec)));
+ if (text_segment != NULL)
+ {
+ iou_write (output_file, text_segment, (output_exec . a_text));
+ iou_free (text_segment);
+ GNU_PAGE_SEEK_TEXT (output_file, output_exec, (output_exec . a_text));
+ }
+ if (data_segment != NULL)
+ {
+ iou_write (output_file, data_segment, (output_exec . a_data));
+ iou_free (data_segment);
+ GNU_PAGE_SEEK_TEXT (output_file, output_exec, (output_exec . a_data));
+ }
+ write_relocation_info
+ (output_file, text_relocation_info, text_relocation_info_length);
+ write_relocation_info
+ (output_file, data_relocation_info, data_relocation_info_length);
+ write_symbol_table (output_file, symbol_table, symbol_table_length);
+
+ return;
+}
+
+/* Convert an archive file. */
+
+/* These procedures take advantage of the fact that the HP and GNU
+ formats for struct ar_hdr are virtually identical. */
+
+long symtab_start_position;
+char *symtab_member_data;
+struct hp_ar_symtab_entry *hp_symtab_entries;
+struct gnu_symdef *gnu_symtab_entries;
+long symtab_entries_length;
+long symtab_names_length;
+
+void
+process_archive_file (input_file, output_file)
+ int input_file;
+ int output_file;
+{
+ int start_position;
+ int length;
+ struct hp_ar_hdr input_header;
+ int member_length;
+ forward void process_archive_symtab ();
+ forward void update_symtab_entries ();
+ forward void output_symtab_entries ();
+ forward void process_archive_entry ();
+
+ gnu_symtab_entries = NULL;
+ while (1)
+ {
+ start_position = (iou_lseek (input_file, 0, 1));
+ length = (read (input_file, (& input_header), (sizeof (input_header))));
+ if (length == 0)
+ break;
+ if (length != (sizeof (input_header)))
+ iou_error ("input archive ends prematurely");
+ if (((strncmp
+ ((input_header . ar_fmag),
+ HP_ARFMAG,
+ (sizeof (input_header . ar_fmag))))
+ != 0)
+ ||
+ ((sscanf ((input_header . ar_size), "%d", (& member_length)))
+ != 1))
+ iou_error ("malformatted header of archive member");
+
+ if (((input_header . ar_name) [0]) == '/')
+ process_archive_symtab
+ (input_file, output_file, (& input_header), member_length);
+ else
+ {
+ if (gnu_symtab_entries != NULL)
+ update_symtab_entries
+ (start_position, (iou_lseek (output_file, 0, 1)));
+ process_archive_entry (input_file, output_file, (& input_header),
+ member_length);
+ }
+ }
+ if (gnu_symtab_entries != NULL)
+ output_symtab_entries (output_file, (& input_header));
+ return;
+}
+
+#ifdef DEBUG_SYMTAB
+
+void
+dump_symtab_data ()
+{
+ register struct hp_ar_symtab_entry *symtab_entries;
+ register char *symtab_names;
+ register int i;
+
+ symtab_names = (symtab_member_data + (sizeof (struct hp_ar_symtab_hdr)));
+ symtab_entries =
+ ((struct hp_ar_symtab_entry *) (symtab_names + symtab_names_length));
+ for (i = 0; (i < symtab_entries_length); i += 1)
+ {
+ fprintf
+ (stdout,
+ "Entry %d: string_index = %d; file_index = %d; name = %s\n",
+ i,
+ ((symtab_entries [i]) . string_index),
+ ((symtab_entries [i]) . file_index),
+ (symtab_names + ((symtab_entries [i]) . string_index)));
+ }
+ fflush (stdout);
+ return;
+}
+
+#endif /* DEBUG_SYMTAB */
+
+void
+process_archive_symtab (input_file, output_file, input_header, member_length)
+ int input_file;
+ int output_file;
+ struct hp_ar_hdr *input_header;
+ int member_length;
+{
+ long symtab_entries_bytes;
+ void initialize_symtab_entries ();
+
+ symtab_member_data = (iou_malloc (member_length));
+ xread (input_file, symtab_member_data, member_length);
+
+ symtab_entries_length =
+ (((struct hp_ar_symtab_hdr *) symtab_member_data) -> n_entries);
+ symtab_entries_bytes =
+ (symtab_entries_length * (sizeof (struct hp_ar_symtab_entry)));
+ symtab_names_length =
+ (((struct hp_ar_symtab_hdr *) symtab_member_data) -> string_table_size);
+
+#ifdef DEBUG_SYMTAB
+ dump_symtab_data ();
+#endif
+
+ {
+ char string_buffer [((sizeof (input_header -> ar_name)) + 1)];
+
+ sprintf
+ (string_buffer, "%-*s", (sizeof (input_header -> ar_name)), "__.SYMDEF");
+ strncpy
+ ((input_header -> ar_name),
+ string_buffer,
+ (sizeof (input_header -> ar_name)));
+ }
+ {
+ char string_buffer [((sizeof (input_header -> ar_size)) + 1)];
+
+ sprintf
+ (string_buffer,
+ "%-*d",
+ (sizeof (input_header -> ar_size)),
+ (symtab_entries_bytes + symtab_names_length + (2 * (sizeof (long)))));
+ strncpy
+ ((input_header -> ar_size),
+ string_buffer,
+ (sizeof (input_header -> ar_size)));
+ }
+ iou_write (output_file, input_header, (sizeof (* input_header)));
+ iou_write (output_file, (& symtab_entries_bytes), (sizeof (long)));
+
+ /* Leave slot for entries, which we fill in later. */
+ symtab_start_position = (iou_lseek (output_file, 0, 1));
+ initialize_symtab_entries ();
+ iou_lseek (output_file, symtab_entries_bytes, 1);
+
+ iou_write (output_file, (& symtab_names_length), (sizeof (long)));
+ iou_write
+ (output_file,
+ (symtab_member_data + (sizeof (struct hp_ar_symtab_hdr))),
+ symtab_names_length);
+
+ return;
+}
+
+void
+initialize_symtab_entries ()
+{
+ register struct hp_ar_symtab_entry *scan_hp;
+ register struct hp_ar_symtab_entry *end;
+ register struct gnu_symdef *scan_gnu;
+
+ hp_symtab_entries =
+ ((struct hp_ar_symtab_entry *)
+ (symtab_member_data
+ + (sizeof (struct hp_ar_symtab_hdr))
+ + symtab_names_length));
+ gnu_symtab_entries =
+ ((struct gnu_symdef *)
+ (iou_malloc (symtab_entries_length * (sizeof (struct gnu_symdef)))));
+
+ scan_hp = hp_symtab_entries;
+ end = (scan_hp + symtab_entries_length);
+ scan_gnu = gnu_symtab_entries;
+ while (scan_hp < end)
+ {
+ (scan_gnu -> symbol_name_string_index) = (scan_hp -> string_index);
+ (scan_gnu -> library_member_offset) = (-1);
+ scan_hp += 1;
+ scan_gnu += 1;
+ }
+
+ return;
+}
+
+void
+update_symtab_entries (old_offset, new_offset)
+ register long old_offset;
+ long new_offset;
+{
+ register struct hp_ar_symtab_entry *scan_hp;
+ register struct hp_ar_symtab_entry *end;
+ register struct gnu_symdef *scan_gnu;
+
+#ifdef DEBUG_SYMTAB
+ fprintf (stdout, "Update: old = %d, new = %d\n", old_offset, new_offset);
+#endif
+
+ scan_hp = hp_symtab_entries;
+ end = (scan_hp + symtab_entries_length);
+ scan_gnu = gnu_symtab_entries;
+ while (scan_hp < end)
+ {
+ if ((scan_hp -> file_index) == old_offset)
+ {
+#ifdef DEBUG_SYMTAB
+ fprintf
+ (stdout,
+ "\t%s\n",
+ (symtab_member_data
+ + (sizeof (struct hp_ar_symtab_hdr))
+ + (scan -> string_index)));
+#endif
+ (scan_gnu -> library_member_offset) = new_offset;
+ }
+ scan_hp += 1;
+ scan_gnu += 1;
+ }
+ return;
+}
+
+void
+check_symtab_entries ()
+{
+ register struct gnu_symdef *scan;
+ register struct gnu_symdef *end;
+
+ scan = gnu_symtab_entries;
+ end = (scan + symtab_entries_length);
+ while (scan < end)
+ if (((scan++) -> library_member_offset) == (-1))
+ iou_error ("Uninitialized __.SYMTAB entry");
+
+ return;
+}
+
+void
+output_symtab_entries (output_file, input_header)
+ int output_file;
+ struct hp_ar_hdr *input_header;
+{
+ check_symtab_entries ();
+ iou_lseek (output_file, symtab_start_position, 0);
+ iou_write
+ (output_file,
+ gnu_symtab_entries,
+ (symtab_entries_length * (sizeof (struct gnu_symdef))));
+ iou_free (symtab_member_data);
+ iou_free (gnu_symtab_entries);
+ return;
+}
+
+void
+process_archive_entry (input_file, output_file, input_header, member_length)
+ int input_file;
+ int output_file;
+ struct hp_ar_hdr *input_header;
+ int member_length;
+{
+ long header_position;
+ long output_start;
+ long output_end;
+ long input_end;
+ char *slashptr;
+
+ /* Strategy: leave a hole for the header, then process the file.
+ Afterwards, back up and write the header in place. */
+ header_position = (iou_lseek (output_file, 0, 1));
+ output_start = (iou_lseek (output_file, (sizeof (* input_header)), 1));
+ input_end = ((iou_lseek (input_file, 0, 1)) + member_length);
+
+ process_executable_file (input_file, output_file);
+ if ((iou_lseek (input_file, 0, 1)) != input_end)
+ iou_error ("process_executable_file used wrong amount of input");
+
+ output_end = (iou_lseek (output_file, 0, 1));
+ iou_lseek (output_file, header_position, 0);
+ if (slashptr = index(input_header->ar_name, '/'))
+ *slashptr = ' ';
+ {
+ char string_buffer [((sizeof (input_header -> ar_size)) + 1)];
+
+ sprintf
+ (string_buffer,
+ "%-*d",
+ (sizeof (input_header -> ar_size)),
+ (output_end - output_start));
+ strncpy
+ ((input_header -> ar_size),
+ string_buffer,
+ (sizeof (input_header -> ar_size)));
+ }
+ iou_write (output_file, input_header, (sizeof (* input_header)));
+ iou_lseek (output_file, output_end, 0);
+
+ /* Pad to even byte boundary if needed */
+ if ((input_end & 1) != 0)
+ iou_lseek (input_file, 1, 1);
+ if ((output_end & 1) != 0)
+ iou_write (output_file, "\0", 1);
+
+ return;
+}
+
+void
+main (argc, argv)
+ int argc;
+ char *argv[];
+{
+ int input_file;
+ int output_file;
+ register int length;
+ struct hp_magic input_magic;
+
+ iou_set_program_name (argv);
+ if (argc != 3)
+ {
+ fprintf (stderr, "usage: %s input-file output-file\n", iou_program_name);
+ iou_error ();
+ }
+
+ input_file = (iou_open ((argv [1]), O_RDONLY));
+ output_file = (iou_open ((argv [2]), (O_WRONLY | O_CREAT | O_TRUNC), 0666));
+
+ xread (input_file, (& input_magic), (sizeof (input_magic)));
+ if (HP_MAGIC_OK (input_magic))
+ {
+ iou_lseek (input_file, 0, 0);
+ process_executable_file (input_file, output_file);
+ }
+ else
+ {
+ char armag [HP_SARMAG];
+
+ iou_lseek (input_file, 0, 0);
+ xread (input_file, armag, HP_SARMAG);
+ if ((strncmp (armag, HP_ARMAG, HP_SARMAG)) != 0)
+ iou_error ("input file not executable or archive");
+ iou_write (output_file, GNU_ARMAG, GNU_SARMAG);
+ process_archive_file (input_file, output_file);
+ }
+ exit (0);
+ /*NOTREACHED*/
+}