#include "alloca-conf.h"
#include "bfd.h"
#include "sysdep.h"
#if defined (HOST_HPPAHPUX) || defined (HOST_HPPABSD) || defined (HOST_HPPAOSF) || defined(HOST_HPPAMPEIX)
#include "libbfd.h"
#include "som.h"
#include "safe-ctype.h"
#include <sys/param.h>
#include <signal.h>
#include <machine/reg.h>
#include <sys/file.h>
static bfd_reloc_status_type hppa_som_reloc
(bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
static bfd_boolean som_mkobject (bfd *);
static bfd_boolean som_is_space (asection *);
static bfd_boolean som_is_subspace (asection *);
static int compare_subspaces (const void *, const void *);
static unsigned long som_compute_checksum (bfd *);
static bfd_boolean som_build_and_write_symbol_table (bfd *);
static unsigned int som_slurp_symbol_table (bfd *);
#ifndef CPU_PA_RISC1_0
#define CPU_PA_RISC1_0 0x20B
#endif
#ifndef CPU_PA_RISC1_1
#define CPU_PA_RISC1_1 0x210
#endif
#ifndef CPU_PA_RISC2_0
#define CPU_PA_RISC2_0 0x214
#endif
#ifndef _PA_RISC1_0_ID
#define _PA_RISC1_0_ID CPU_PA_RISC1_0
#endif
#ifndef _PA_RISC1_1_ID
#define _PA_RISC1_1_ID CPU_PA_RISC1_1
#endif
#ifndef _PA_RISC2_0_ID
#define _PA_RISC2_0_ID CPU_PA_RISC2_0
#endif
#ifndef _PA_RISC_MAXID
#define _PA_RISC_MAXID 0x2FF
#endif
#ifndef _PA_RISC_ID
#define _PA_RISC_ID(__m_num) \
(((__m_num) == _PA_RISC1_0_ID) || \
((__m_num) >= _PA_RISC1_1_ID && (__m_num) <= _PA_RISC_MAXID))
#endif
#ifdef HPUX_AUX_ID
#define EXEC_AUX_ID HPUX_AUX_ID
#endif
#if !defined (EXEC_AUX_ID) && defined (HIUX_AUX_ID)
#define EXEC_AUX_ID HIUX_AUX_ID
#endif
#ifndef EXEC_AUX_ID
#define EXEC_AUX_ID 0
#endif
#define SOM_TMP_BUFSIZE 8192
#define SOM_LST_HASH_SIZE 31
#define SOM_LST_MODULE_LIMIT 1024
#define SOM_ALIGN(val, alignment) \
(((val) + (alignment) - 1) &~ ((unsigned long) (alignment) - 1))
struct reloc_queue
{
unsigned char *reloc;
unsigned int size;
} reloc_queue[4];
typedef enum
{
SYMBOL_TYPE_UNKNOWN,
SYMBOL_TYPE_ABSOLUTE,
SYMBOL_TYPE_CODE,
SYMBOL_TYPE_DATA,
SYMBOL_TYPE_ENTRY,
SYMBOL_TYPE_MILLICODE,
SYMBOL_TYPE_PLABEL,
SYMBOL_TYPE_PRI_PROG,
SYMBOL_TYPE_SEC_PROG,
} pa_symbol_type;
struct section_to_type
{
char *section;
char type;
};
struct som_misc_symbol_info
{
unsigned int symbol_type;
unsigned int symbol_scope;
unsigned int arg_reloc;
unsigned int symbol_info;
unsigned int symbol_value;
unsigned int priv_level;
unsigned int secondary_def;
unsigned int is_comdat;
unsigned int is_common;
unsigned int dup_common;
};
static const struct section_to_type stt[] =
{
{"$TEXT$", 't'},
{"$SHLIB_INFO$", 't'},
{"$MILLICODE$", 't'},
{"$LIT$", 't'},
{"$CODE$", 't'},
{"$UNWIND_START$", 't'},
{"$UNWIND$", 't'},
{"$PRIVATE$", 'd'},
{"$PLT$", 'd'},
{"$SHLIB_DATA$", 'd'},
{"$DATA$", 'd'},
{"$SHORTDATA$", 'g'},
{"$DLT$", 'd'},
{"$GLOBAL$", 'g'},
{"$SHORTBSS$", 's'},
{"$BSS$", 'b'},
{"$GDB_STRINGS$", 'N'},
{"$GDB_SYMBOLS$", 'N'},
{0, 0}
};
struct fixup_format
{
int D;
const char *format;
};
static const struct fixup_format som_fixup_formats[256] =
{
{ 0, "LD1+4*=" },
{ 1, "LD1+4*=" },
{ 2, "LD1+4*=" },
{ 3, "LD1+4*=" },
{ 4, "LD1+4*=" },
{ 5, "LD1+4*=" },
{ 6, "LD1+4*=" },
{ 7, "LD1+4*=" },
{ 8, "LD1+4*=" },
{ 9, "LD1+4*=" },
{ 10, "LD1+4*=" },
{ 11, "LD1+4*=" },
{ 12, "LD1+4*=" },
{ 13, "LD1+4*=" },
{ 14, "LD1+4*=" },
{ 15, "LD1+4*=" },
{ 16, "LD1+4*=" },
{ 17, "LD1+4*=" },
{ 18, "LD1+4*=" },
{ 19, "LD1+4*=" },
{ 20, "LD1+4*=" },
{ 21, "LD1+4*=" },
{ 22, "LD1+4*=" },
{ 23, "LD1+4*=" },
{ 0, "LD8<b+1+4*=" },
{ 1, "LD8<b+1+4*=" },
{ 2, "LD8<b+1+4*=" },
{ 3, "LD8<b+1+4*=" },
{ 0, "LD16<c+1+4*=" },
{ 1, "LD16<c+1+4*=" },
{ 2, "LD16<c+1+4*=" },
{ 0, "Ld1+=" },
{ 0, "Lb1+4*=" },
{ 1, "Ld1+=" },
{ 0, "Lb1+4*=" },
{ 1, "Ld1+=" },
{ 0, "L4=" },
{ 0, "L4=Sb=" },
{ 1, "L4=Sd=" },
{ 0, "L4=Sb=" },
{ 1, "L4=Sd=" },
{ 0, "L4=" },
{ 0, "L4=Mb1+4*=" },
{ 1, "Lb4*=Mb1+L*=" },
{ 2, "Lb4*=Md1+4*=" },
{ 3, "Ld1+=Me1+=" },
{ 0, "" },
{ 0, "" },
{ 0, "L4=RD=Sb=" },
{ 1, "L4=RD=Sb=" },
{ 2, "L4=RD=Sb=" },
{ 3, "L4=RD=Sb=" },
{ 4, "L4=RD=Sb=" },
{ 5, "L4=RD=Sb=" },
{ 6, "L4=RD=Sb=" },
{ 7, "L4=RD=Sb=" },
{ 8, "L4=RD=Sb=" },
{ 9, "L4=RD=Sb=" },
{ 0, "L4=RD8<b+=Sb=" },
{ 1, "L4=RD8<b+=Sb=" },
{ 0, "L4=RD8<b+=Sd=" },
{ 1, "L4=RD8<b+=Sd=" },
{ 0, "" },
{ 0, "" },
{ 0, "L4=RD=Sb=" },
{ 1, "L4=RD=Sb=" },
{ 2, "L4=RD=Sb=" },
{ 3, "L4=RD=Sb=" },
{ 4, "L4=RD=Sb=" },
{ 5, "L4=RD=Sb=" },
{ 6, "L4=RD=Sb=" },
{ 7, "L4=RD=Sb=" },
{ 8, "L4=RD=Sb=" },
{ 9, "L4=RD=Sb=" },
{ 0, "L4=RD8<b+=Sb=" },
{ 1, "L4=RD8<b+=Sb=" },
{ 0, "L4=RD8<b+=Sd=" },
{ 1, "L4=RD8<b+=Sd=" },
{ 0, "" },
{ 0, "" },
{ 0, "L4=SD=" },
{ 1, "L4=SD=" },
{ 2, "L4=SD=" },
{ 3, "L4=SD=" },
{ 4, "L4=SD=" },
{ 5, "L4=SD=" },
{ 6, "L4=SD=" },
{ 7, "L4=SD=" },
{ 8, "L4=SD=" },
{ 9, "L4=SD=" },
{ 10, "L4=SD=" },
{ 11, "L4=SD=" },
{ 12, "L4=SD=" },
{ 13, "L4=SD=" },
{ 14, "L4=SD=" },
{ 15, "L4=SD=" },
{ 16, "L4=SD=" },
{ 17, "L4=SD=" },
{ 18, "L4=SD=" },
{ 19, "L4=SD=" },
{ 20, "L4=SD=" },
{ 21, "L4=SD=" },
{ 22, "L4=SD=" },
{ 23, "L4=SD=" },
{ 24, "L4=SD=" },
{ 25, "L4=SD=" },
{ 26, "L4=SD=" },
{ 27, "L4=SD=" },
{ 28, "L4=SD=" },
{ 29, "L4=SD=" },
{ 30, "L4=SD=" },
{ 31, "L4=SD=" },
{ 32, "L4=Sb=" },
{ 33, "L4=Sd=" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "L4=Sb=" },
{ 1, "L4=Sd=" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "L4=SD=" },
{ 1, "L4=SD=" },
{ 2, "L4=SD=" },
{ 3, "L4=SD=" },
{ 4, "L4=SD=" },
{ 5, "L4=SD=" },
{ 6, "L4=SD=" },
{ 7, "L4=SD=" },
{ 8, "L4=SD=" },
{ 9, "L4=SD=" },
{ 10, "L4=SD=" },
{ 11, "L4=SD=" },
{ 12, "L4=SD=" },
{ 13, "L4=SD=" },
{ 14, "L4=SD=" },
{ 15, "L4=SD=" },
{ 16, "L4=SD=" },
{ 17, "L4=SD=" },
{ 18, "L4=SD=" },
{ 19, "L4=SD=" },
{ 20, "L4=SD=" },
{ 21, "L4=SD=" },
{ 22, "L4=SD=" },
{ 23, "L4=SD=" },
{ 24, "L4=SD=" },
{ 25, "L4=SD=" },
{ 26, "L4=SD=" },
{ 27, "L4=SD=" },
{ 28, "L4=SD=" },
{ 29, "L4=SD=" },
{ 30, "L4=SD=" },
{ 31, "L4=SD=" },
{ 32, "L4=Sb=" },
{ 33, "L4=Sd=" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "L4=Sb=" },
{ 1, "L4=Sd=" },
{ 0, "L4=Sb=" },
{ 1, "L4=Sd=" },
{ 0, "L4=" },
{ 0, "Te=Ue=" },
{ 1, "Uf=" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "R0=" },
{ 1, "Rb4*=" },
{ 2, "Rd4*=" },
{ 0, "" },
{ 0, "" },
{ 0, "Nb=" },
{ 1, "Nc=" },
{ 2, "Nd=" },
{ 0, "L4=" },
{ 0, "L4=" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "V0=" },
{ 1, "Vb=" },
{ 2, "Vc=" },
{ 3, "Vd=" },
{ 4, "Ve=" },
{ 0, "" },
{ 0,"Sd=Ve=Ee=" },
{ 0, "Ob=" },
{ 0, "Ob=Sd=" },
{ 0, "Ob=Ve=" },
{ 0, "P" },
{ 1, "P" },
{ 2, "P" },
{ 3, "P" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "Eb=Sd=Ve=" },
{ 0, "Eb=Mb=" },
{ 0, "" },
{ 0, "Ob=Vf=" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
{ 0, "" },
};
static const int comp1_opcodes[] =
{
0x00,
0x40,
0x41,
0x42,
0x43,
0x44,
0x45,
0x46,
0x47,
0x48,
0x49,
0x4a,
0x4b,
0x60,
0x80,
0xa0,
0xc0,
-1
};
static const int comp2_opcodes[] =
{
0x00,
0x80,
0x82,
0xc0,
-1
};
static const int comp3_opcodes[] =
{
0x00,
0x02,
-1
};
#ifndef R_DLT_REL
#define R_DLT_REL 0x78
#endif
#ifndef R_AUX_UNWIND
#define R_AUX_UNWIND 0xcf
#endif
#ifndef R_SEC_STMT
#define R_SEC_STMT 0xd7
#endif
#ifndef R_SHORT_PCREL_MODE
#define NO_PCREL_MODES
#define R_SHORT_PCREL_MODE 0x3e
#endif
#ifndef R_LONG_PCREL_MODE
#define R_LONG_PCREL_MODE 0x3f
#endif
#ifndef R_N0SEL
#define R_N0SEL 0xd8
#endif
#ifndef R_N1SEL
#define R_N1SEL 0xd9
#endif
#ifndef R_LINETAB
#define R_LINETAB 0xda
#endif
#ifndef R_LINETAB_ESC
#define R_LINETAB_ESC 0xdb
#endif
#ifndef R_LTP_OVERRIDE
#define R_LTP_OVERRIDE 0xdc
#endif
#ifndef R_COMMENT
#define R_COMMENT 0xdd
#endif
#define SOM_HOWTO(TYPE, NAME) \
HOWTO(TYPE, 0, 0, 32, FALSE, 0, 0, hppa_som_reloc, NAME, FALSE, 0, 0, FALSE)
static reloc_howto_type som_hppa_howto_table[] =
{
SOM_HOWTO (R_NO_RELOCATION, "R_NO_RELOCATION"),
SOM_HOWTO (R_NO_RELOCATION, "R_NO_RELOCATION"),
SOM_HOWTO (R_NO_RELOCATION, "R_NO_RELOCATION"),
SOM_HOWTO (R_NO_RELOCATION, "R_NO_RELOCATION"),
SOM_HOWTO (R_NO_RELOCATION, "R_NO_RELOCATION"),
SOM_HOWTO (R_NO_RELOCATION, "R_NO_RELOCATION"),
SOM_HOWTO (R_NO_RELOCATION, "R_NO_RELOCATION"),
SOM_HOWTO (R_NO_RELOCATION, "R_NO_RELOCATION"),
SOM_HOWTO (R_NO_RELOCATION, "R_NO_RELOCATION"),
SOM_HOWTO (R_NO_RELOCATION, "R_NO_RELOCATION"),
SOM_HOWTO (R_NO_RELOCATION, "R_NO_RELOCATION"),
SOM_HOWTO (R_NO_RELOCATION, "R_NO_RELOCATION"),
SOM_HOWTO (R_NO_RELOCATION, "R_NO_RELOCATION"),
SOM_HOWTO (R_NO_RELOCATION, "R_NO_RELOCATION"),
SOM_HOWTO (R_NO_RELOCATION, "R_NO_RELOCATION"),
SOM_HOWTO (R_NO_RELOCATION, "R_NO_RELOCATION"),
SOM_HOWTO (R_NO_RELOCATION, "R_NO_RELOCATION"),
SOM_HOWTO (R_NO_RELOCATION, "R_NO_RELOCATION"),
SOM_HOWTO (R_NO_RELOCATION, "R_NO_RELOCATION"),
SOM_HOWTO (R_NO_RELOCATION, "R_NO_RELOCATION"),
SOM_HOWTO (R_NO_RELOCATION, "R_NO_RELOCATION"),
SOM_HOWTO (R_NO_RELOCATION, "R_NO_RELOCATION"),
SOM_HOWTO (R_NO_RELOCATION, "R_NO_RELOCATION"),
SOM_HOWTO (R_NO_RELOCATION, "R_NO_RELOCATION"),
SOM_HOWTO (R_NO_RELOCATION, "R_NO_RELOCATION"),
SOM_HOWTO (R_NO_RELOCATION, "R_NO_RELOCATION"),
SOM_HOWTO (R_NO_RELOCATION, "R_NO_RELOCATION"),
SOM_HOWTO (R_NO_RELOCATION, "R_NO_RELOCATION"),
SOM_HOWTO (R_NO_RELOCATION, "R_NO_RELOCATION"),
SOM_HOWTO (R_NO_RELOCATION, "R_NO_RELOCATION"),
SOM_HOWTO (R_NO_RELOCATION, "R_NO_RELOCATION"),
SOM_HOWTO (R_NO_RELOCATION, "R_NO_RELOCATION"),
SOM_HOWTO (R_ZEROES, "R_ZEROES"),
SOM_HOWTO (R_ZEROES, "R_ZEROES"),
SOM_HOWTO (R_UNINIT, "R_UNINIT"),
SOM_HOWTO (R_UNINIT, "R_UNINIT"),
SOM_HOWTO (R_RELOCATION, "R_RELOCATION"),
SOM_HOWTO (R_DATA_ONE_SYMBOL, "R_DATA_ONE_SYMBOL"),
SOM_HOWTO (R_DATA_ONE_SYMBOL, "R_DATA_ONE_SYMBOL"),
SOM_HOWTO (R_DATA_PLABEL, "R_DATA_PLABEL"),
SOM_HOWTO (R_DATA_PLABEL, "R_DATA_PLABEL"),
SOM_HOWTO (R_SPACE_REF, "R_SPACE_REF"),
SOM_HOWTO (R_REPEATED_INIT, "REPEATED_INIT"),
SOM_HOWTO (R_REPEATED_INIT, "REPEATED_INIT"),
SOM_HOWTO (R_REPEATED_INIT, "REPEATED_INIT"),
SOM_HOWTO (R_REPEATED_INIT, "REPEATED_INIT"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_PCREL_CALL, "R_PCREL_CALL"),
SOM_HOWTO (R_PCREL_CALL, "R_PCREL_CALL"),
SOM_HOWTO (R_PCREL_CALL, "R_PCREL_CALL"),
SOM_HOWTO (R_PCREL_CALL, "R_PCREL_CALL"),
SOM_HOWTO (R_PCREL_CALL, "R_PCREL_CALL"),
SOM_HOWTO (R_PCREL_CALL, "R_PCREL_CALL"),
SOM_HOWTO (R_PCREL_CALL, "R_PCREL_CALL"),
SOM_HOWTO (R_PCREL_CALL, "R_PCREL_CALL"),
SOM_HOWTO (R_PCREL_CALL, "R_PCREL_CALL"),
SOM_HOWTO (R_PCREL_CALL, "R_PCREL_CALL"),
SOM_HOWTO (R_PCREL_CALL, "R_PCREL_CALL"),
SOM_HOWTO (R_PCREL_CALL, "R_PCREL_CALL"),
SOM_HOWTO (R_PCREL_CALL, "R_PCREL_CALL"),
SOM_HOWTO (R_PCREL_CALL, "R_PCREL_CALL"),
SOM_HOWTO (R_SHORT_PCREL_MODE, "R_SHORT_PCREL_MODE"),
SOM_HOWTO (R_LONG_PCREL_MODE, "R_LONG_PCREL_MODE"),
SOM_HOWTO (R_ABS_CALL, "R_ABS_CALL"),
SOM_HOWTO (R_ABS_CALL, "R_ABS_CALL"),
SOM_HOWTO (R_ABS_CALL, "R_ABS_CALL"),
SOM_HOWTO (R_ABS_CALL, "R_ABS_CALL"),
SOM_HOWTO (R_ABS_CALL, "R_ABS_CALL"),
SOM_HOWTO (R_ABS_CALL, "R_ABS_CALL"),
SOM_HOWTO (R_ABS_CALL, "R_ABS_CALL"),
SOM_HOWTO (R_ABS_CALL, "R_ABS_CALL"),
SOM_HOWTO (R_ABS_CALL, "R_ABS_CALL"),
SOM_HOWTO (R_ABS_CALL, "R_ABS_CALL"),
SOM_HOWTO (R_ABS_CALL, "R_ABS_CALL"),
SOM_HOWTO (R_ABS_CALL, "R_ABS_CALL"),
SOM_HOWTO (R_ABS_CALL, "R_ABS_CALL"),
SOM_HOWTO (R_ABS_CALL, "R_ABS_CALL"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_DP_RELATIVE, "R_DP_RELATIVE"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_DLT_REL, "R_DLT_REL"),
SOM_HOWTO (R_DLT_REL, "R_DLT_REL"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_CODE_ONE_SYMBOL, "R_CODE_ONE_SYMBOL"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_MILLI_REL, "R_MILLI_REL"),
SOM_HOWTO (R_MILLI_REL, "R_MILLI_REL"),
SOM_HOWTO (R_CODE_PLABEL, "R_CODE_PLABEL"),
SOM_HOWTO (R_CODE_PLABEL, "R_CODE_PLABEL"),
SOM_HOWTO (R_BREAKPOINT, "R_BREAKPOINT"),
SOM_HOWTO (R_ENTRY, "R_ENTRY"),
SOM_HOWTO (R_ENTRY, "R_ENTRY"),
SOM_HOWTO (R_ALT_ENTRY, "R_ALT_ENTRY"),
SOM_HOWTO (R_EXIT, "R_EXIT"),
SOM_HOWTO (R_BEGIN_TRY, "R_BEGIN_TRY"),
SOM_HOWTO (R_END_TRY, "R_END_TRY"),
SOM_HOWTO (R_END_TRY, "R_END_TRY"),
SOM_HOWTO (R_END_TRY, "R_END_TRY"),
SOM_HOWTO (R_BEGIN_BRTAB, "R_BEGIN_BRTAB"),
SOM_HOWTO (R_END_BRTAB, "R_END_BRTAB"),
SOM_HOWTO (R_STATEMENT, "R_STATEMENT"),
SOM_HOWTO (R_STATEMENT, "R_STATEMENT"),
SOM_HOWTO (R_STATEMENT, "R_STATEMENT"),
SOM_HOWTO (R_DATA_EXPR, "R_DATA_EXPR"),
SOM_HOWTO (R_CODE_EXPR, "R_CODE_EXPR"),
SOM_HOWTO (R_FSEL, "R_FSEL"),
SOM_HOWTO (R_LSEL, "R_LSEL"),
SOM_HOWTO (R_RSEL, "R_RSEL"),
SOM_HOWTO (R_N_MODE, "R_N_MODE"),
SOM_HOWTO (R_S_MODE, "R_S_MODE"),
SOM_HOWTO (R_D_MODE, "R_D_MODE"),
SOM_HOWTO (R_R_MODE, "R_R_MODE"),
SOM_HOWTO (R_DATA_OVERRIDE, "R_DATA_OVERRIDE"),
SOM_HOWTO (R_DATA_OVERRIDE, "R_DATA_OVERRIDE"),
SOM_HOWTO (R_DATA_OVERRIDE, "R_DATA_OVERRIDE"),
SOM_HOWTO (R_DATA_OVERRIDE, "R_DATA_OVERRIDE"),
SOM_HOWTO (R_DATA_OVERRIDE, "R_DATA_OVERRIDE"),
SOM_HOWTO (R_TRANSLATED, "R_TRANSLATED"),
SOM_HOWTO (R_AUX_UNWIND, "R_AUX_UNWIND"),
SOM_HOWTO (R_COMP1, "R_COMP1"),
SOM_HOWTO (R_COMP2, "R_COMP2"),
SOM_HOWTO (R_COMP3, "R_COMP3"),
SOM_HOWTO (R_PREV_FIXUP, "R_PREV_FIXUP"),
SOM_HOWTO (R_PREV_FIXUP, "R_PREV_FIXUP"),
SOM_HOWTO (R_PREV_FIXUP, "R_PREV_FIXUP"),
SOM_HOWTO (R_PREV_FIXUP, "R_PREV_FIXUP"),
SOM_HOWTO (R_SEC_STMT, "R_SEC_STMT"),
SOM_HOWTO (R_N0SEL, "R_N0SEL"),
SOM_HOWTO (R_N1SEL, "R_N1SEL"),
SOM_HOWTO (R_LINETAB, "R_LINETAB"),
SOM_HOWTO (R_LINETAB_ESC, "R_LINETAB_ESC"),
SOM_HOWTO (R_LTP_OVERRIDE, "R_LTP_OVERRIDE"),
SOM_HOWTO (R_COMMENT, "R_COMMENT"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED"),
SOM_HOWTO (R_RESERVED, "R_RESERVED")
};
static void
som_initialize_reloc_queue (struct reloc_queue *queue)
{
queue[0].reloc = NULL;
queue[0].size = 0;
queue[1].reloc = NULL;
queue[1].size = 0;
queue[2].reloc = NULL;
queue[2].size = 0;
queue[3].reloc = NULL;
queue[3].size = 0;
}
static void
som_reloc_queue_insert (unsigned char *p,
unsigned int size,
struct reloc_queue *queue)
{
queue[3].reloc = queue[2].reloc;
queue[3].size = queue[2].size;
queue[2].reloc = queue[1].reloc;
queue[2].size = queue[1].size;
queue[1].reloc = queue[0].reloc;
queue[1].size = queue[0].size;
queue[0].reloc = p;
queue[0].size = size;
}
static void
som_reloc_queue_fix (struct reloc_queue *queue, unsigned int index)
{
if (index == 0)
return;
if (index == 1)
{
unsigned char *tmp1 = queue[0].reloc;
unsigned int tmp2 = queue[0].size;
queue[0].reloc = queue[1].reloc;
queue[0].size = queue[1].size;
queue[1].reloc = tmp1;
queue[1].size = tmp2;
return;
}
if (index == 2)
{
unsigned char *tmp1 = queue[0].reloc;
unsigned int tmp2 = queue[0].size;
queue[0].reloc = queue[2].reloc;
queue[0].size = queue[2].size;
queue[2].reloc = queue[1].reloc;
queue[2].size = queue[1].size;
queue[1].reloc = tmp1;
queue[1].size = tmp2;
return;
}
if (index == 3)
{
unsigned char *tmp1 = queue[0].reloc;
unsigned int tmp2 = queue[0].size;
queue[0].reloc = queue[3].reloc;
queue[0].size = queue[3].size;
queue[3].reloc = queue[2].reloc;
queue[3].size = queue[2].size;
queue[2].reloc = queue[1].reloc;
queue[2].size = queue[1].size;
queue[1].reloc = tmp1;
queue[1].size = tmp2;
return;
}
abort ();
}
static int
som_reloc_queue_find (unsigned char *p,
unsigned int size,
struct reloc_queue *queue)
{
if (queue[0].reloc && !memcmp (p, queue[0].reloc, size)
&& size == queue[0].size)
return 0;
if (queue[1].reloc && !memcmp (p, queue[1].reloc, size)
&& size == queue[1].size)
return 1;
if (queue[2].reloc && !memcmp (p, queue[2].reloc, size)
&& size == queue[2].size)
return 2;
if (queue[3].reloc && !memcmp (p, queue[3].reloc, size)
&& size == queue[3].size)
return 3;
return -1;
}
static unsigned char *
try_prev_fixup (bfd *abfd ATTRIBUTE_UNUSED,
unsigned int *subspace_reloc_sizep,
unsigned char *p,
unsigned int size,
struct reloc_queue *queue)
{
int queue_index = som_reloc_queue_find (p, size, queue);
if (queue_index != -1)
{
bfd_put_8 (abfd, R_PREV_FIXUP + queue_index, p);
p += 1;
*subspace_reloc_sizep += 1;
som_reloc_queue_fix (queue, queue_index);
}
else
{
som_reloc_queue_insert (p, size, queue);
*subspace_reloc_sizep += size;
p += size;
}
return p;
}
static unsigned char *
som_reloc_skip (bfd *abfd,
unsigned int skip,
unsigned char *p,
unsigned int *subspace_reloc_sizep,
struct reloc_queue *queue)
{
if (skip >= 0x1000000)
{
skip -= 0x1000000;
bfd_put_8 (abfd, R_NO_RELOCATION + 31, p);
bfd_put_8 (abfd, 0xff, p + 1);
bfd_put_16 (abfd, (bfd_vma) 0xffff, p + 2);
p = try_prev_fixup (abfd, subspace_reloc_sizep, p, 4, queue);
while (skip >= 0x1000000)
{
skip -= 0x1000000;
bfd_put_8 (abfd, R_PREV_FIXUP, p);
p++;
*subspace_reloc_sizep += 1;
}
}
if ((skip & 3) == 0 && skip <= 0xc0000 && skip > 0)
{
if (skip <= 0x60)
{
bfd_put_8 (abfd, R_NO_RELOCATION + (skip >> 2) - 1, p);
*subspace_reloc_sizep += 1;
p++;
}
else if (skip <= 0x1000)
{
bfd_put_8 (abfd, R_NO_RELOCATION + 24 + (((skip >> 2) - 1) >> 8), p);
bfd_put_8 (abfd, (skip >> 2) - 1, p + 1);
p = try_prev_fixup (abfd, subspace_reloc_sizep, p, 2, queue);
}
else
{
bfd_put_8 (abfd, R_NO_RELOCATION + 28 + (((skip >> 2) - 1) >> 16), p);
bfd_put_16 (abfd, (bfd_vma) (skip >> 2) - 1, p + 1);
p = try_prev_fixup (abfd, subspace_reloc_sizep, p, 3, queue);
}
}
else if (skip > 0)
{
bfd_put_8 (abfd, R_NO_RELOCATION + 31, p);
bfd_put_8 (abfd, (skip - 1) >> 16, p + 1);
bfd_put_16 (abfd, (bfd_vma) skip - 1, p + 2);
p = try_prev_fixup (abfd, subspace_reloc_sizep, p, 4, queue);
}
return p;
}
static unsigned char *
som_reloc_addend (bfd *abfd,
bfd_vma addend,
unsigned char *p,
unsigned int *subspace_reloc_sizep,
struct reloc_queue *queue)
{
if (addend + 0x80 < 0x100)
{
bfd_put_8 (abfd, R_DATA_OVERRIDE + 1, p);
bfd_put_8 (abfd, addend, p + 1);
p = try_prev_fixup (abfd, subspace_reloc_sizep, p, 2, queue);
}
else if (addend + 0x8000 < 0x10000)
{
bfd_put_8 (abfd, R_DATA_OVERRIDE + 2, p);
bfd_put_16 (abfd, addend, p + 1);
p = try_prev_fixup (abfd, subspace_reloc_sizep, p, 3, queue);
}
else if (addend + 0x800000 < 0x1000000)
{
bfd_put_8 (abfd, R_DATA_OVERRIDE + 3, p);
bfd_put_8 (abfd, addend >> 16, p + 1);
bfd_put_16 (abfd, addend, p + 2);
p = try_prev_fixup (abfd, subspace_reloc_sizep, p, 4, queue);
}
else
{
bfd_put_8 (abfd, R_DATA_OVERRIDE + 4, p);
bfd_put_32 (abfd, addend, p + 1);
p = try_prev_fixup (abfd, subspace_reloc_sizep, p, 5, queue);
}
return p;
}
static unsigned char *
som_reloc_call (bfd *abfd,
unsigned char *p,
unsigned int *subspace_reloc_sizep,
arelent *bfd_reloc,
int sym_num,
struct reloc_queue *queue)
{
int arg_bits = HPPA_R_ARG_RELOC (bfd_reloc->addend);
int rtn_bits = arg_bits & 0x3;
int type, done = 0;
if (sym_num < 0x100)
{
switch (arg_bits)
{
case 0:
case 1:
type = 0;
break;
case 1 << 8:
case 1 << 8 | 1:
type = 1;
break;
case 1 << 8 | 1 << 6:
case 1 << 8 | 1 << 6 | 1:
type = 2;
break;
case 1 << 8 | 1 << 6 | 1 << 4:
case 1 << 8 | 1 << 6 | 1 << 4 | 1:
type = 3;
break;
case 1 << 8 | 1 << 6 | 1 << 4 | 1 << 2:
case 1 << 8 | 1 << 6 | 1 << 4 | 1 << 2 | 1:
type = 4;
break;
default:
type = -1;
break;
}
if (type != -1)
{
if (rtn_bits)
type += 5;
bfd_put_8 (abfd, bfd_reloc->howto->type + type, p);
bfd_put_8 (abfd, sym_num, p + 1);
p = try_prev_fixup (abfd, subspace_reloc_sizep, p, 2, queue);
done = 1;
}
}
if (! done)
{
type = rtn_bits;
if ((arg_bits >> 6 & 0xf) == 0xe)
type += 9 * 40;
else
type += (3 * (arg_bits >> 8 & 3) + (arg_bits >> 6 & 3)) * 40;
if ((arg_bits >> 2 & 0xf) == 0xe)
type += 9 * 4;
else
type += (3 * (arg_bits >> 4 & 3) + (arg_bits >> 2 & 3)) * 4;
bfd_put_8 (abfd, bfd_reloc->howto->type + 10
+ 2 * (sym_num >= 0x100) + (type >= 0x100),
p);
bfd_put_8 (abfd, type, p + 1);
if (sym_num < 0x100)
{
bfd_put_8 (abfd, sym_num, p + 2);
p = try_prev_fixup (abfd, subspace_reloc_sizep, p, 3, queue);
}
else
{
bfd_put_8 (abfd, sym_num >> 16, p + 2);
bfd_put_16 (abfd, (bfd_vma) sym_num, p + 3);
p = try_prev_fixup (abfd, subspace_reloc_sizep, p, 5, queue);
}
}
return p;
}
static int
exact_log2 (unsigned int x)
{
int log = 0;
if (x == 0 || x != (x & -x))
return -1;
while ((x >>= 1) != 0)
log++;
return log;
}
static bfd_reloc_status_type
hppa_som_reloc (bfd *abfd ATTRIBUTE_UNUSED,
arelent *reloc_entry,
asymbol *symbol_in ATTRIBUTE_UNUSED,
void *data ATTRIBUTE_UNUSED,
asection *input_section,
bfd *output_bfd,
char **error_message ATTRIBUTE_UNUSED)
{
if (output_bfd)
reloc_entry->address += input_section->output_offset;
return bfd_reloc_ok;
}
int **
hppa_som_gen_reloc_type (bfd *abfd,
int base_type,
int format,
enum hppa_reloc_field_selector_type_alt field,
int sym_diff,
asymbol *sym)
{
int *final_type, **final_types;
final_types = bfd_alloc (abfd, (bfd_size_type) sizeof (int *) * 6);
final_type = bfd_alloc (abfd, (bfd_size_type) sizeof (int));
if (!final_types || !final_type)
return NULL;
switch (field)
{
case e_fsel:
case e_psel:
case e_lpsel:
case e_rpsel:
final_types[0] = final_type;
final_types[1] = NULL;
final_types[2] = NULL;
*final_type = base_type;
break;
case e_tsel:
case e_ltsel:
case e_rtsel:
final_types[0] = bfd_alloc (abfd, (bfd_size_type) sizeof (int));
if (!final_types[0])
return NULL;
if (field == e_tsel)
*final_types[0] = R_FSEL;
else if (field == e_ltsel)
*final_types[0] = R_LSEL;
else
*final_types[0] = R_RSEL;
final_types[1] = final_type;
final_types[2] = NULL;
*final_type = base_type;
break;
case e_lssel:
case e_rssel:
final_types[0] = bfd_alloc (abfd, (bfd_size_type) sizeof (int));
if (!final_types[0])
return NULL;
*final_types[0] = R_S_MODE;
final_types[1] = final_type;
final_types[2] = NULL;
*final_type = base_type;
break;
case e_lsel:
case e_rsel:
final_types[0] = bfd_alloc (abfd, (bfd_size_type) sizeof (int));
if (!final_types[0])
return NULL;
*final_types[0] = R_N_MODE;
final_types[1] = final_type;
final_types[2] = NULL;
*final_type = base_type;
break;
case e_ldsel:
case e_rdsel:
final_types[0] = bfd_alloc (abfd, (bfd_size_type) sizeof (int));
if (!final_types[0])
return NULL;
*final_types[0] = R_D_MODE;
final_types[1] = final_type;
final_types[2] = NULL;
*final_type = base_type;
break;
case e_lrsel:
case e_rrsel:
final_types[0] = bfd_alloc (abfd, (bfd_size_type) sizeof (int));
if (!final_types[0])
return NULL;
*final_types[0] = R_R_MODE;
final_types[1] = final_type;
final_types[2] = NULL;
*final_type = base_type;
break;
case e_nsel:
final_types[0] = bfd_alloc (abfd, (bfd_size_type) sizeof (int));
if (!final_types[0])
return NULL;
*final_types[0] = R_N1SEL;
final_types[1] = final_type;
final_types[2] = NULL;
*final_type = base_type;
break;
case e_nlsel:
case e_nlrsel:
final_types[0] = bfd_alloc (abfd, (bfd_size_type) sizeof (int));
if (!final_types[0])
return NULL;
*final_types[0] = R_N0SEL;
final_types[1] = bfd_alloc (abfd, (bfd_size_type) sizeof (int));
if (!final_types[1])
return NULL;
if (field == e_nlsel)
*final_types[1] = R_N_MODE;
else
*final_types[1] = R_R_MODE;
final_types[2] = final_type;
final_types[3] = NULL;
*final_type = base_type;
break;
case e_ltpsel:
case e_rtpsel:
abort ();
}
switch (base_type)
{
case R_HPPA:
if (sym_diff)
{
bfd_size_type amt = sizeof (int);
final_types[0] = bfd_alloc (abfd, amt);
final_types[1] = bfd_alloc (abfd, amt);
final_types[2] = bfd_alloc (abfd, amt);
final_types[3] = bfd_alloc (abfd, amt);
if (!final_types[0] || !final_types[1] || !final_types[2])
return NULL;
if (field == e_fsel)
*final_types[0] = R_FSEL;
else if (field == e_rsel)
*final_types[0] = R_RSEL;
else if (field == e_lsel)
*final_types[0] = R_LSEL;
*final_types[1] = R_COMP2;
*final_types[2] = R_COMP2;
*final_types[3] = R_COMP1;
final_types[4] = final_type;
if (format == 32)
*final_types[4] = R_DATA_EXPR;
else
*final_types[4] = R_CODE_EXPR;
final_types[5] = NULL;
break;
}
else if (field == e_psel
|| field == e_lpsel
|| field == e_rpsel)
{
if (format == 32)
*final_type = R_DATA_PLABEL;
else
*final_type = R_CODE_PLABEL;
}
else if (field == e_tsel
|| field == e_ltsel
|| field == e_rtsel)
*final_type = R_DLT_REL;
else if (format == 32)
{
*final_type = R_DATA_ONE_SYMBOL;
if (som_symbol_data (sym)->som_type == SYMBOL_TYPE_UNKNOWN
&& (sym->flags & BSF_SECTION_SYM) == 0
&& (sym->flags & BSF_FUNCTION) == 0
&& ! bfd_is_com_section (sym->section))
som_symbol_data (sym)->som_type = SYMBOL_TYPE_DATA;
}
break;
case R_HPPA_GOTOFF:
if (field == e_psel
|| field == e_lpsel
|| field == e_rpsel)
*final_type = R_DATA_PLABEL;
break;
case R_HPPA_COMPLEX:
if (sym_diff)
{
bfd_size_type amt = sizeof (int);
final_types[0] = bfd_alloc (abfd, amt);
final_types[1] = bfd_alloc (abfd, amt);
final_types[2] = bfd_alloc (abfd, amt);
final_types[3] = bfd_alloc (abfd, amt);
if (!final_types[0] || !final_types[1] || !final_types[2])
return NULL;
if (field == e_fsel)
*final_types[0] = R_FSEL;
else if (field == e_rsel)
*final_types[0] = R_RSEL;
else if (field == e_lsel)
*final_types[0] = R_LSEL;
*final_types[1] = R_COMP2;
*final_types[2] = R_COMP2;
*final_types[3] = R_COMP1;
final_types[4] = final_type;
if (format == 32)
*final_types[4] = R_DATA_EXPR;
else
*final_types[4] = R_CODE_EXPR;
final_types[5] = NULL;
break;
}
else
break;
case R_HPPA_NONE:
case R_HPPA_ABS_CALL:
break;
case R_HPPA_PCREL_CALL:
{
#ifndef NO_PCREL_MODES
bfd_size_type amt = sizeof (int);
final_types[0] = bfd_alloc (abfd, amt);
if (!final_types[0])
return NULL;
if (format == 17)
*final_types[0] = R_SHORT_PCREL_MODE;
else
*final_types[0] = R_LONG_PCREL_MODE;
final_types[1] = final_type;
final_types[2] = NULL;
*final_type = base_type;
#endif
break;
}
}
return final_types;
}
static reloc_howto_type *
som_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
bfd_reloc_code_real_type code)
{
if ((int) code < (int) R_NO_RELOCATION + 255)
{
BFD_ASSERT ((int) som_hppa_howto_table[(int) code].type == (int) code);
return &som_hppa_howto_table[(int) code];
}
return NULL;
}
static const bfd_target *
som_object_setup (bfd *abfd,
struct header *file_hdrp,
struct som_exec_auxhdr *aux_hdrp,
unsigned long current_offset)
{
asection *section;
if (! som_mkobject (abfd))
return NULL;
abfd->flags = BFD_NO_FLAGS;
if (file_hdrp->symbol_total)
abfd->flags |= HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS;
switch (file_hdrp->a_magic)
{
case DEMAND_MAGIC:
abfd->flags |= (D_PAGED | WP_TEXT | EXEC_P);
break;
case SHARE_MAGIC:
abfd->flags |= (WP_TEXT | EXEC_P);
break;
case EXEC_MAGIC:
abfd->flags |= (EXEC_P);
break;
case RELOC_MAGIC:
abfd->flags |= HAS_RELOC;
break;
#ifdef SHL_MAGIC
case SHL_MAGIC:
#endif
#ifdef DL_MAGIC
case DL_MAGIC:
#endif
abfd->flags |= DYNAMIC;
break;
default:
break;
}
obj_som_exec_hdr (abfd) = aux_hdrp;
obj_som_exec_data (abfd) = bfd_zalloc (abfd, (bfd_size_type) sizeof (struct som_exec_data));
if (obj_som_exec_data (abfd) == NULL)
return NULL;
if (aux_hdrp)
{
int found = 0;
for (section = abfd->sections; section; section = section->next)
{
bfd_vma entry;
if ((section->flags & SEC_CODE) == 0)
continue;
entry = aux_hdrp->exec_entry + aux_hdrp->exec_tmem;
if (entry >= section->vma
&& entry < section->vma + section->size)
found = 1;
}
if ((aux_hdrp->exec_entry == 0 && !(abfd->flags & DYNAMIC))
|| (aux_hdrp->exec_entry & 0x3) != 0
|| ! found)
{
bfd_get_start_address (abfd) = aux_hdrp->exec_flags;
obj_som_exec_data (abfd)->exec_flags = aux_hdrp->exec_entry;
}
else
{
bfd_get_start_address (abfd) = aux_hdrp->exec_entry + current_offset;
obj_som_exec_data (abfd)->exec_flags = aux_hdrp->exec_flags;
}
}
obj_som_exec_data (abfd)->version_id = file_hdrp->version_id;
bfd_default_set_arch_mach (abfd, bfd_arch_hppa, pa10);
bfd_get_symcount (abfd) = file_hdrp->symbol_total;
obj_som_stringtab (abfd) = NULL;
obj_som_symtab (abfd) = NULL;
obj_som_sorted_syms (abfd) = NULL;
obj_som_stringtab_size (abfd) = file_hdrp->symbol_strings_size;
obj_som_sym_filepos (abfd) = file_hdrp->symbol_location + current_offset;
obj_som_str_filepos (abfd) = (file_hdrp->symbol_strings_location
+ current_offset);
obj_som_reloc_filepos (abfd) = (file_hdrp->fixup_request_location
+ current_offset);
obj_som_exec_data (abfd)->system_id = file_hdrp->system_id;
return abfd->xvec;
}
static bfd_boolean
setup_sections (bfd *abfd,
struct header *file_hdr,
unsigned long current_offset)
{
char *space_strings;
unsigned int space_index, i;
unsigned int total_subspaces = 0;
asection **subspace_sections = NULL;
asection *section;
bfd_size_type amt;
amt = file_hdr->space_strings_size;
space_strings = bfd_malloc (amt);
if (!space_strings && amt != 0)
goto error_return;
if (bfd_seek (abfd, current_offset + file_hdr->space_strings_location,
SEEK_SET) != 0)
goto error_return;
if (bfd_bread (space_strings, amt, abfd) != amt)
goto error_return;
for (space_index = 0; space_index < file_hdr->space_total; space_index++)
{
struct space_dictionary_record space;
struct som_subspace_dictionary_record subspace, save_subspace;
unsigned int subspace_index;
asection *space_asect;
bfd_size_type space_size = 0;
char *newname;
if (bfd_seek (abfd,
(current_offset + file_hdr->space_location
+ space_index * sizeof space),
SEEK_SET) != 0)
goto error_return;
amt = sizeof space;
if (bfd_bread (&space, amt, abfd) != amt)
goto error_return;
space.name.n_name = space.name.n_strx + space_strings;
amt = strlen (space.name.n_name) + 1;
newname = bfd_alloc (abfd, amt);
if (!newname)
goto error_return;
strcpy (newname, space.name.n_name);
space_asect = bfd_make_section_anyway (abfd, newname);
if (!space_asect)
goto error_return;
if (space.is_loadable == 0)
space_asect->flags |= SEC_DEBUGGING;
if (! bfd_som_set_section_attributes (space_asect, space.is_defined,
space.is_private, space.sort_key,
space.space_number))
goto error_return;
if (space.subspace_quantity == 0)
continue;
if (bfd_seek (abfd,
(current_offset + file_hdr->subspace_location
+ space.subspace_index * sizeof subspace),
SEEK_SET) != 0)
goto error_return;
amt = sizeof subspace;
if (bfd_bread (&subspace, amt, abfd) != amt)
goto error_return;
if (bfd_seek (abfd,
(current_offset + file_hdr->subspace_location
+ space.subspace_index * sizeof subspace),
SEEK_SET) != 0)
goto error_return;
space_asect->vma = subspace.subspace_start;
space_asect->filepos = subspace.file_loc_init_value + current_offset;
space_asect->alignment_power = exact_log2 (subspace.alignment);
if (space_asect->alignment_power == (unsigned) -1)
goto error_return;
memset (&save_subspace, 0, sizeof (save_subspace));
for (subspace_index = 0; subspace_index < space.subspace_quantity;
subspace_index++)
{
asection *subspace_asect;
amt = sizeof subspace;
if (bfd_bread (&subspace, amt, abfd) != amt)
goto error_return;
subspace.name.n_name = subspace.name.n_strx + space_strings;
amt = strlen (subspace.name.n_name) + 1;
newname = bfd_alloc (abfd, amt);
if (!newname)
goto error_return;
strcpy (newname, subspace.name.n_name);
subspace_asect = bfd_make_section_anyway (abfd, newname);
if (!subspace_asect)
goto error_return;
if (! bfd_som_set_subsection_attributes (subspace_asect, space_asect,
subspace.access_control_bits,
subspace.sort_key,
subspace.quadrant,
subspace.is_comdat,
subspace.is_common,
subspace.dup_common))
goto error_return;
total_subspaces++;
subspace_asect->target_index = bfd_tell (abfd) - sizeof (subspace);
switch (subspace.access_control_bits >> 4)
{
case 0x0:
subspace_asect->flags |= SEC_DATA | SEC_READONLY;
break;
case 0x1:
subspace_asect->flags |= SEC_DATA;
break;
case 0x2:
case 0x4:
case 0x5:
case 0x6:
case 0x7:
subspace_asect->flags |= SEC_CODE | SEC_READONLY;
break;
case 0x3:
subspace_asect->flags |= SEC_CODE;
break;
}
if (subspace.is_comdat || subspace.is_common || subspace.dup_common)
subspace_asect->flags |= SEC_LINK_ONCE;
if (subspace.subspace_length > 0)
subspace_asect->flags |= SEC_HAS_CONTENTS;
if (subspace.is_loadable)
subspace_asect->flags |= SEC_ALLOC | SEC_LOAD;
else
subspace_asect->flags |= SEC_DEBUGGING;
if (subspace.code_only)
subspace_asect->flags |= SEC_CODE;
if (subspace.file_loc_init_value == 0
&& subspace.initialization_length == 0)
subspace_asect->flags &= ~(SEC_DATA | SEC_LOAD | SEC_HAS_CONTENTS);
if (subspace.fixup_request_quantity != 0)
{
subspace_asect->flags |= SEC_RELOC;
subspace_asect->rel_filepos = subspace.fixup_request_index;
som_section_data (subspace_asect)->reloc_size
= subspace.fixup_request_quantity;
subspace_asect->reloc_count = (unsigned) -1;
}
if (subspace.file_loc_init_value > save_subspace.file_loc_init_value)
save_subspace = subspace;
subspace_asect->vma = subspace.subspace_start;
subspace_asect->size = subspace.subspace_length;
subspace_asect->filepos = (subspace.file_loc_init_value
+ current_offset);
subspace_asect->alignment_power = exact_log2 (subspace.alignment);
if (subspace_asect->alignment_power == (unsigned) -1)
goto error_return;
space_size += subspace.subspace_length;
}
if (!save_subspace.file_loc_init_value)
space_asect->size = 0;
else
{
if (file_hdr->a_magic != RELOC_MAGIC)
{
space_asect->size = (save_subspace.subspace_start
- space_asect->vma
+ save_subspace.subspace_length);
}
else
{
space_asect->size = space_size;
}
}
}
amt = total_subspaces;
amt *= sizeof (asection *);
subspace_sections = bfd_malloc (amt);
if (subspace_sections == NULL)
goto error_return;
for (i = 0, section = abfd->sections; section; section = section->next)
{
if (!som_is_subspace (section))
continue;
subspace_sections[i] = section;
i++;
}
qsort (subspace_sections, total_subspaces,
sizeof (asection *), compare_subspaces);
for (i = 0; i < total_subspaces; i++)
subspace_sections[i]->target_index = i;
if (space_strings != NULL)
free (space_strings);
if (subspace_sections != NULL)
free (subspace_sections);
return TRUE;
error_return:
if (space_strings != NULL)
free (space_strings);
if (subspace_sections != NULL)
free (subspace_sections);
return FALSE;
}
static const bfd_target *
som_object_p (bfd *abfd)
{
struct header file_hdr;
struct som_exec_auxhdr *aux_hdr_ptr = NULL;
unsigned long current_offset = 0;
struct lst_header lst_header;
struct som_entry som_entry;
bfd_size_type amt;
#define ENTRY_SIZE sizeof (struct som_entry)
amt = FILE_HDR_SIZE;
if (bfd_bread ((void *) &file_hdr, amt, abfd) != amt)
{
if (bfd_get_error () != bfd_error_system_call)
bfd_set_error (bfd_error_wrong_format);
return NULL;
}
if (!_PA_RISC_ID (file_hdr.system_id))
{
bfd_set_error (bfd_error_wrong_format);
return NULL;
}
switch (file_hdr.a_magic)
{
case RELOC_MAGIC:
case EXEC_MAGIC:
case SHARE_MAGIC:
case DEMAND_MAGIC:
#ifdef DL_MAGIC
case DL_MAGIC:
#endif
#ifdef SHL_MAGIC
case SHL_MAGIC:
#endif
#ifdef SHARED_MAGIC_CNX
case SHARED_MAGIC_CNX:
#endif
break;
#ifdef EXECLIBMAGIC
case EXECLIBMAGIC:
if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
{
if (bfd_get_error () != bfd_error_system_call)
bfd_set_error (bfd_error_wrong_format);
return NULL;
}
amt = SLSTHDR;
if (bfd_bread ((void *) &lst_header, amt, abfd) != amt)
{
if (bfd_get_error () != bfd_error_system_call)
bfd_set_error (bfd_error_wrong_format);
return NULL;
}
if (bfd_seek (abfd, lst_header.dir_loc, SEEK_SET) != 0)
{
if (bfd_get_error () != bfd_error_system_call)
bfd_set_error (bfd_error_wrong_format);
return NULL;
}
amt = ENTRY_SIZE;
if (bfd_bread ((void *) &som_entry, amt, abfd) != amt)
{
if (bfd_get_error () != bfd_error_system_call)
bfd_set_error (bfd_error_wrong_format);
return NULL;
}
if (bfd_seek (abfd, som_entry.location, SEEK_SET) != 0)
{
if (bfd_get_error () != bfd_error_system_call)
bfd_set_error (bfd_error_wrong_format);
return NULL;
}
current_offset = som_entry.location;
amt = FILE_HDR_SIZE;
if (bfd_bread ((void *) &file_hdr, amt, abfd) != amt)
{
if (bfd_get_error () != bfd_error_system_call)
bfd_set_error (bfd_error_wrong_format);
return NULL;
}
break;
#endif
default:
bfd_set_error (bfd_error_wrong_format);
return NULL;
}
if (file_hdr.version_id != VERSION_ID
&& file_hdr.version_id != NEW_VERSION_ID)
{
bfd_set_error (bfd_error_wrong_format);
return NULL;
}
if (file_hdr.aux_header_size != 0)
{
aux_hdr_ptr = bfd_zalloc (abfd,
(bfd_size_type) sizeof (*aux_hdr_ptr));
if (aux_hdr_ptr == NULL)
return NULL;
amt = AUX_HDR_SIZE;
if (bfd_bread ((void *) aux_hdr_ptr, amt, abfd) != amt)
{
if (bfd_get_error () != bfd_error_system_call)
bfd_set_error (bfd_error_wrong_format);
return NULL;
}
}
if (!setup_sections (abfd, &file_hdr, current_offset))
{
bfd_set_error (bfd_error_bad_value);
return NULL;
}
return som_object_setup (abfd, &file_hdr, aux_hdr_ptr, current_offset);
}
static bfd_boolean
som_mkobject (bfd *abfd)
{
abfd->tdata.som_data = bfd_zalloc (abfd, (bfd_size_type) sizeof (struct som_data_struct));
if (abfd->tdata.som_data == NULL)
return FALSE;
return TRUE;
}
static bfd_boolean
som_prep_headers (bfd *abfd)
{
struct header *file_hdr;
asection *section;
bfd_size_type amt = sizeof (struct header);
file_hdr = bfd_zalloc (abfd, amt);
if (file_hdr == NULL)
return FALSE;
obj_som_file_hdr (abfd) = file_hdr;
if (abfd->flags & (EXEC_P | DYNAMIC))
{
amt = sizeof (struct som_exec_auxhdr);
obj_som_exec_hdr (abfd) = bfd_zalloc (abfd, amt);
if (obj_som_exec_hdr (abfd) == NULL)
return FALSE;
if (abfd->flags & D_PAGED)
file_hdr->a_magic = DEMAND_MAGIC;
else if (abfd->flags & WP_TEXT)
file_hdr->a_magic = SHARE_MAGIC;
#ifdef SHL_MAGIC
else if (abfd->flags & DYNAMIC)
file_hdr->a_magic = SHL_MAGIC;
#endif
else
file_hdr->a_magic = EXEC_MAGIC;
}
else
file_hdr->a_magic = RELOC_MAGIC;
file_hdr->file_time.secs = 0;
file_hdr->file_time.nanosecs = 0;
file_hdr->entry_space = 0;
file_hdr->entry_subspace = 0;
file_hdr->entry_offset = 0;
file_hdr->presumed_dp = 0;
for (section = abfd->sections; section != NULL; section = section->next)
{
if (!som_is_space (section) && !som_is_subspace (section))
continue;
if (som_is_space (section))
{
amt = sizeof (struct space_dictionary_record);
som_section_data (section)->space_dict = bfd_zalloc (abfd, amt);
if (som_section_data (section)->space_dict == NULL)
return FALSE;
som_section_data (section)->space_dict->loader_fix_index = -1;
som_section_data (section)->space_dict->init_pointer_index = -1;
som_section_data (section)->space_dict->sort_key =
som_section_data (section)->copy_data->sort_key;
som_section_data (section)->space_dict->is_defined =
som_section_data (section)->copy_data->is_defined;
som_section_data (section)->space_dict->is_private =
som_section_data (section)->copy_data->is_private;
som_section_data (section)->space_dict->space_number =
som_section_data (section)->copy_data->space_number;
}
else
{
amt = sizeof (struct som_subspace_dictionary_record);
som_section_data (section)->subspace_dict = bfd_zalloc (abfd, amt);
if (som_section_data (section)->subspace_dict == NULL)
return FALSE;
if (section->flags & SEC_ALLOC)
som_section_data (section)->subspace_dict->is_loadable = 1;
if (section->flags & SEC_CODE)
som_section_data (section)->subspace_dict->code_only = 1;
som_section_data (section)->subspace_dict->subspace_start =
section->vma;
som_section_data (section)->subspace_dict->subspace_length =
section->size;
som_section_data (section)->subspace_dict->initialization_length =
section->size;
som_section_data (section)->subspace_dict->alignment =
1 << section->alignment_power;
som_section_data (section)->subspace_dict->sort_key =
som_section_data (section)->copy_data->sort_key;
som_section_data (section)->subspace_dict->access_control_bits =
som_section_data (section)->copy_data->access_control_bits;
som_section_data (section)->subspace_dict->quadrant =
som_section_data (section)->copy_data->quadrant;
som_section_data (section)->subspace_dict->is_comdat =
som_section_data (section)->copy_data->is_comdat;
som_section_data (section)->subspace_dict->is_common =
som_section_data (section)->copy_data->is_common;
som_section_data (section)->subspace_dict->dup_common =
som_section_data (section)->copy_data->dup_common;
}
}
return TRUE;
}
static bfd_boolean
som_is_space (asection *section)
{
if (som_section_data (section)->copy_data == NULL)
return FALSE;
if (som_section_data (section)->copy_data->container != section
&& (som_section_data (section)->copy_data->container->output_section
!= section))
return FALSE;
return TRUE;
}
static bfd_boolean
som_is_subspace (asection *section)
{
if (som_section_data (section)->copy_data == NULL)
return FALSE;
if (som_section_data (section)->copy_data->container == section
|| (som_section_data (section)->copy_data->container->output_section
== section))
return FALSE;
return TRUE;
}
static bfd_boolean
som_is_container (asection *space, asection *subspace)
{
return (som_section_data (subspace)->copy_data->container == space)
|| (som_section_data (subspace)->copy_data->container->output_section
== space);
}
static unsigned long
som_count_spaces (bfd *abfd)
{
int count = 0;
asection *section;
for (section = abfd->sections; section != NULL; section = section->next)
count += som_is_space (section);
return count;
}
static unsigned long
som_count_subspaces (bfd *abfd)
{
int count = 0;
asection *section;
for (section = abfd->sections; section != NULL; section = section->next)
count += som_is_subspace (section);
return count;
}
static int
compare_syms (const void *arg1, const void *arg2)
{
asymbol **sym1 = (asymbol **) arg1;
asymbol **sym2 = (asymbol **) arg2;
unsigned int count1, count2;
if ((*sym1)->flags & BSF_SECTION_SYM)
count1 = (*sym1)->udata.i;
else
count1 = som_symbol_data (*sym1)->reloc_count;
if ((*sym2)->flags & BSF_SECTION_SYM)
count2 = (*sym2)->udata.i;
else
count2 = som_symbol_data (*sym2)->reloc_count;
if (count1 < count2)
return 1;
else if (count1 > count2)
return -1;
return 0;
}
static int
compare_subspaces (const void *arg1, const void *arg2)
{
asection **subspace1 = (asection **) arg1;
asection **subspace2 = (asection **) arg2;
if ((*subspace1)->target_index < (*subspace2)->target_index)
return -1;
else if ((*subspace2)->target_index < (*subspace1)->target_index)
return 1;
else
return 0;
}
static void
som_prep_for_fixups (bfd *abfd, asymbol **syms, unsigned long num_syms)
{
unsigned long i;
asection *section;
asymbol **sorted_syms;
bfd_size_type amt;
for (i = 0; i < num_syms; i++)
{
if (som_symbol_data (syms[i]) == NULL
|| syms[i]->flags & BSF_SECTION_SYM)
{
syms[i]->flags |= BSF_SECTION_SYM;
syms[i]->udata.i = 0;
}
else
som_symbol_data (syms[i])->reloc_count = 0;
}
for (section = abfd->sections; section != NULL; section = section->next)
{
int j;
if ((int) section->reloc_count <= 0)
continue;
for (j = 1; j < (int) section->reloc_count; j++)
{
arelent *reloc = section->orelocation[j];
int scale;
if (reloc->sym_ptr_ptr == NULL
|| bfd_is_abs_section ((*reloc->sym_ptr_ptr)->section))
continue;
if (reloc->howto->type == R_DP_RELATIVE
|| reloc->howto->type == R_CODE_ONE_SYMBOL)
scale = 2;
else
scale = 1;
if ((*reloc->sym_ptr_ptr)->flags & BSF_SECTION_SYM)
{
(*reloc->sym_ptr_ptr)->udata.i =
(*reloc->sym_ptr_ptr)->udata.i + scale;
continue;
}
som_symbol_data (*reloc->sym_ptr_ptr)->reloc_count += scale;
}
}
amt = num_syms;
amt *= sizeof (asymbol *);
sorted_syms = bfd_zalloc (abfd, amt);
memcpy (sorted_syms, syms, num_syms * sizeof (asymbol *));
qsort (sorted_syms, num_syms, sizeof (asymbol *), compare_syms);
obj_som_sorted_syms (abfd) = sorted_syms;
for (i = 0; i < num_syms; i++)
{
if (sorted_syms[i]->flags & BSF_SECTION_SYM)
sorted_syms[i]->udata.i = i;
else
som_symbol_data (sorted_syms[i])->index = i;
}
}
static bfd_boolean
som_write_fixups (bfd *abfd,
unsigned long current_offset,
unsigned int *total_reloc_sizep)
{
unsigned int i, j;
unsigned char tmp_space[SOM_TMP_BUFSIZE];
unsigned char *p;
unsigned int total_reloc_size = 0;
unsigned int subspace_reloc_size = 0;
unsigned int num_spaces = obj_som_file_hdr (abfd)->space_total;
asection *section = abfd->sections;
bfd_size_type amt;
memset (tmp_space, 0, SOM_TMP_BUFSIZE);
p = tmp_space;
for (i = 0; i < num_spaces; i++)
{
asection *subsection;
while (!som_is_space (section))
section = section->next;
for (subsection = abfd->sections;
subsection != NULL;
subsection = subsection->next)
{
int reloc_offset;
unsigned int current_rounding_mode;
#ifndef NO_PCREL_MODES
unsigned int current_call_mode;
#endif
if (!som_is_subspace (subsection)
|| !som_is_container (section, subsection))
continue;
if ((subsection->flags & SEC_HAS_CONTENTS) == 0)
{
som_section_data (subsection)->subspace_dict->fixup_request_index
= -1;
continue;
}
som_section_data (subsection)->subspace_dict->fixup_request_index
= total_reloc_size;
if (bfd_seek (abfd, current_offset + total_reloc_size, SEEK_SET) != 0)
return FALSE;
p = tmp_space;
subspace_reloc_size = 0;
reloc_offset = 0;
som_initialize_reloc_queue (reloc_queue);
current_rounding_mode = R_N_MODE;
#ifndef NO_PCREL_MODES
current_call_mode = R_SHORT_PCREL_MODE;
#endif
for (j = 0; j < subsection->reloc_count; j++)
{
arelent *bfd_reloc = subsection->orelocation[j];
unsigned int skip;
int sym_num;
if ((*bfd_reloc->sym_ptr_ptr)->flags & BSF_SECTION_SYM)
sym_num = (*bfd_reloc->sym_ptr_ptr)->udata.i;
else
sym_num = som_symbol_data (*bfd_reloc->sym_ptr_ptr)->index;
if (p - tmp_space + 100 > SOM_TMP_BUFSIZE)
{
amt = p - tmp_space;
if (bfd_bwrite ((void *) tmp_space, amt, abfd) != amt)
return FALSE;
p = tmp_space;
som_initialize_reloc_queue (reloc_queue);
}
skip = bfd_reloc->address - reloc_offset;
p = som_reloc_skip (abfd, skip, p,
&subspace_reloc_size, reloc_queue);
switch (bfd_reloc->howto->type)
{
case R_ENTRY:
case R_ALT_ENTRY:
case R_EXIT:
case R_N_MODE:
case R_S_MODE:
case R_D_MODE:
case R_R_MODE:
case R_FSEL:
case R_LSEL:
case R_RSEL:
case R_COMP1:
case R_COMP2:
case R_BEGIN_BRTAB:
case R_END_BRTAB:
case R_BEGIN_TRY:
case R_END_TRY:
case R_N0SEL:
case R_N1SEL:
#ifndef NO_PCREL_MODES
case R_SHORT_PCREL_MODE:
case R_LONG_PCREL_MODE:
#endif
reloc_offset = bfd_reloc->address;
break;
default:
reloc_offset = bfd_reloc->address + 4;
break;
}
switch (bfd_reloc->howto->type)
{
case R_PCREL_CALL:
case R_ABS_CALL:
p = som_reloc_call (abfd, p, &subspace_reloc_size,
bfd_reloc, sym_num, reloc_queue);
break;
case R_CODE_ONE_SYMBOL:
case R_DP_RELATIVE:
if (bfd_reloc->addend)
p = som_reloc_addend (abfd, bfd_reloc->addend, p,
&subspace_reloc_size, reloc_queue);
if (sym_num < 0x20)
{
bfd_put_8 (abfd, bfd_reloc->howto->type + sym_num, p);
subspace_reloc_size += 1;
p += 1;
}
else if (sym_num < 0x100)
{
bfd_put_8 (abfd, bfd_reloc->howto->type + 32, p);
bfd_put_8 (abfd, sym_num, p + 1);
p = try_prev_fixup (abfd, &subspace_reloc_size, p,
2, reloc_queue);
}
else if (sym_num < 0x10000000)
{
bfd_put_8 (abfd, bfd_reloc->howto->type + 33, p);
bfd_put_8 (abfd, sym_num >> 16, p + 1);
bfd_put_16 (abfd, (bfd_vma) sym_num, p + 2);
p = try_prev_fixup (abfd, &subspace_reloc_size,
p, 4, reloc_queue);
}
else
abort ();
break;
case R_DATA_ONE_SYMBOL:
case R_DATA_PLABEL:
case R_CODE_PLABEL:
case R_DLT_REL:
if (bfd_reloc->howto->type != R_DATA_ONE_SYMBOL
&& bfd_reloc->addend)
p = som_reloc_addend (abfd, bfd_reloc->addend, p,
&subspace_reloc_size, reloc_queue);
if (sym_num < 0x100)
{
bfd_put_8 (abfd, bfd_reloc->howto->type, p);
bfd_put_8 (abfd, sym_num, p + 1);
p = try_prev_fixup (abfd, &subspace_reloc_size, p,
2, reloc_queue);
}
else if (sym_num < 0x10000000)
{
bfd_put_8 (abfd, bfd_reloc->howto->type + 1, p);
bfd_put_8 (abfd, sym_num >> 16, p + 1);
bfd_put_16 (abfd, (bfd_vma) sym_num, p + 2);
p = try_prev_fixup (abfd, &subspace_reloc_size,
p, 4, reloc_queue);
}
else
abort ();
break;
case R_ENTRY:
{
unsigned int tmp;
arelent *tmp_reloc = NULL;
bfd_put_8 (abfd, R_ENTRY, p);
bfd_put_32 (abfd, bfd_reloc->addend, p + 1);
for (tmp = j; tmp < subsection->reloc_count; tmp++)
{
tmp_reloc = subsection->orelocation[tmp];
if (tmp_reloc->howto->type == R_EXIT)
break;
}
if (tmp == subsection->reloc_count)
abort ();
bfd_put_32 (abfd, tmp_reloc->addend, p + 5);
p = try_prev_fixup (abfd, &subspace_reloc_size,
p, 9, reloc_queue);
break;
}
case R_N_MODE:
case R_S_MODE:
case R_D_MODE:
case R_R_MODE:
if (bfd_reloc->howto->type != current_rounding_mode)
{
bfd_put_8 (abfd, bfd_reloc->howto->type, p);
subspace_reloc_size += 1;
p += 1;
current_rounding_mode = bfd_reloc->howto->type;
}
break;
#ifndef NO_PCREL_MODES
case R_LONG_PCREL_MODE:
case R_SHORT_PCREL_MODE:
if (bfd_reloc->howto->type != current_call_mode)
{
bfd_put_8 (abfd, bfd_reloc->howto->type, p);
subspace_reloc_size += 1;
p += 1;
current_call_mode = bfd_reloc->howto->type;
}
break;
#endif
case R_EXIT:
case R_ALT_ENTRY:
case R_FSEL:
case R_LSEL:
case R_RSEL:
case R_BEGIN_BRTAB:
case R_END_BRTAB:
case R_BEGIN_TRY:
case R_N0SEL:
case R_N1SEL:
bfd_put_8 (abfd, bfd_reloc->howto->type, p);
subspace_reloc_size += 1;
p += 1;
break;
case R_END_TRY:
if (bfd_reloc->addend == 0)
bfd_put_8 (abfd, bfd_reloc->howto->type, p);
else if (bfd_reloc->addend < 1024)
{
bfd_put_8 (abfd, bfd_reloc->howto->type + 1, p);
bfd_put_8 (abfd, bfd_reloc->addend / 4, p + 1);
p = try_prev_fixup (abfd, &subspace_reloc_size,
p, 2, reloc_queue);
}
else
{
bfd_put_8 (abfd, bfd_reloc->howto->type + 2, p);
bfd_put_8 (abfd, (bfd_reloc->addend / 4) >> 16, p + 1);
bfd_put_16 (abfd, bfd_reloc->addend / 4, p + 2);
p = try_prev_fixup (abfd, &subspace_reloc_size,
p, 4, reloc_queue);
}
break;
case R_COMP1:
bfd_put_8 (abfd, bfd_reloc->howto->type, p);
bfd_put_8 (abfd, 0x44, p + 1);
p = try_prev_fixup (abfd, &subspace_reloc_size,
p, 2, reloc_queue);
break;
case R_COMP2:
bfd_put_8 (abfd, bfd_reloc->howto->type, p);
bfd_put_8 (abfd, 0x80, p + 1);
bfd_put_8 (abfd, sym_num >> 16, p + 2);
bfd_put_16 (abfd, (bfd_vma) sym_num, p + 3);
p = try_prev_fixup (abfd, &subspace_reloc_size,
p, 5, reloc_queue);
break;
case R_CODE_EXPR:
case R_DATA_EXPR:
bfd_put_8 (abfd, bfd_reloc->howto->type, p);
subspace_reloc_size += 1;
p += 1;
break;
default:
bfd_put_8 (abfd, 0xff, p);
subspace_reloc_size += 1;
p += 1;
break;
}
}
p = som_reloc_skip (abfd, subsection->size - reloc_offset,
p, &subspace_reloc_size, reloc_queue);
amt = p - tmp_space;
if (bfd_bwrite ((void *) tmp_space, amt, abfd) != amt)
return FALSE;
p = tmp_space;
total_reloc_size += subspace_reloc_size;
som_section_data (subsection)->subspace_dict->fixup_request_quantity
= subspace_reloc_size;
}
section = section->next;
}
*total_reloc_sizep = total_reloc_size;
return TRUE;
}
static bfd_boolean
som_write_space_strings (bfd *abfd,
unsigned long current_offset,
unsigned int *string_sizep)
{
size_t tmp_space_size = SOM_TMP_BUFSIZE;
char *tmp_space = alloca (tmp_space_size);
char *p = tmp_space;
unsigned int strings_size = 0;
asection *section;
bfd_size_type amt;
if (bfd_seek (abfd, (file_ptr) current_offset, SEEK_SET) != 0)
return FALSE;
for (section = abfd->sections; section != NULL; section = section->next)
{
size_t length;
if (!som_is_space (section) && !som_is_subspace (section))
continue;
length = strlen (section->name);
if (p - tmp_space + 5 + length > tmp_space_size)
{
amt = p - tmp_space;
if (bfd_bwrite ((void *) &tmp_space[0], amt, abfd) != amt)
return FALSE;
if (5 + length > tmp_space_size)
{
tmp_space_size = MAX (2 * tmp_space_size, 5 + length);
tmp_space = alloca (tmp_space_size);
}
p = tmp_space;
}
bfd_put_32 (abfd, (bfd_vma) length, p);
p += 4;
strings_size += 4;
if (som_is_space (section))
som_section_data (section)->space_dict->name.n_strx = strings_size;
else
som_section_data (section)->subspace_dict->name.n_strx = strings_size;
strcpy (p, section->name);
p += length + 1;
strings_size += length + 1;
while (strings_size % 4)
{
bfd_put_8 (abfd, 0, p);
p++;
strings_size++;
}
}
amt = p - tmp_space;
if (bfd_bwrite ((void *) &tmp_space[0], amt, abfd) != amt)
return FALSE;
*string_sizep = strings_size;
return TRUE;
}
static bfd_boolean
som_write_symbol_strings (bfd *abfd,
unsigned long current_offset,
asymbol **syms,
unsigned int num_syms,
unsigned int *string_sizep,
COMPUNIT *compilation_unit)
{
unsigned int i;
size_t tmp_space_size = SOM_TMP_BUFSIZE;
char *tmp_space = alloca (tmp_space_size);
char *p = tmp_space;
unsigned int strings_size = 0;
char *comp[4];
bfd_size_type amt;
if (compilation_unit)
{
comp[0] = compilation_unit->name.n_name;
comp[1] = compilation_unit->language_name.n_name;
comp[2] = compilation_unit->product_id.n_name;
comp[3] = compilation_unit->version_id.n_name;
}
if (bfd_seek (abfd, (file_ptr) current_offset, SEEK_SET) != 0)
return FALSE;
if (compilation_unit)
{
for (i = 0; i < 4; i++)
{
size_t length = strlen (comp[i]);
if (p - tmp_space + 5 + length > tmp_space_size)
{
amt = p - tmp_space;
if (bfd_bwrite ((void *) &tmp_space[0], amt, abfd) != amt)
return FALSE;
if (5 + length > tmp_space_size)
{
tmp_space_size = MAX (2 * tmp_space_size, 5 + length);
tmp_space = alloca (tmp_space_size);
}
p = tmp_space;
}
bfd_put_32 (abfd, (bfd_vma) length, p);
strings_size += 4;
p += 4;
strcpy (p, comp[i]);
switch (i)
{
case 0:
obj_som_compilation_unit (abfd)->name.n_strx = strings_size;
break;
case 1:
obj_som_compilation_unit (abfd)->language_name.n_strx =
strings_size;
break;
case 2:
obj_som_compilation_unit (abfd)->product_id.n_strx =
strings_size;
break;
case 3:
obj_som_compilation_unit (abfd)->version_id.n_strx =
strings_size;
break;
}
p += length + 1;
strings_size += length + 1;
while (strings_size % 4)
{
bfd_put_8 (abfd, 0, p);
strings_size++;
p++;
}
}
}
for (i = 0; i < num_syms; i++)
{
size_t length = strlen (syms[i]->name);
if (p - tmp_space + 5 + length > tmp_space_size)
{
amt = p - tmp_space;
if (bfd_bwrite ((void *) &tmp_space[0], amt, abfd) != amt)
return FALSE;
if (5 + length > tmp_space_size)
{
tmp_space_size = MAX (2 * tmp_space_size, 5 + length);
tmp_space = alloca (tmp_space_size);
}
p = tmp_space;
}
bfd_put_32 (abfd, (bfd_vma) length, p);
strings_size += 4;
p += 4;
strcpy (p, syms[i]->name);
som_symbol_data (syms[i])->stringtab_offset = strings_size;
p += length + 1;
strings_size += length + 1;
while (strings_size % 4)
{
bfd_put_8 (abfd, 0, p);
strings_size++;
p++;
}
}
amt = p - tmp_space;
if (bfd_bwrite ((void *) &tmp_space[0], amt, abfd) != amt)
return FALSE;
*string_sizep = strings_size;
return TRUE;
}
static bfd_boolean
som_begin_writing (bfd *abfd)
{
unsigned long current_offset = 0;
unsigned int strings_size = 0;
unsigned long num_spaces, num_subspaces, i;
asection *section;
unsigned int total_subspaces = 0;
struct som_exec_auxhdr *exec_header = NULL;
current_offset += sizeof (struct header);
obj_som_file_hdr (abfd)->aux_header_location = current_offset;
obj_som_file_hdr (abfd)->aux_header_size = 0;
if (abfd->flags & (EXEC_P | DYNAMIC))
{
current_offset += sizeof (struct som_exec_auxhdr);
obj_som_file_hdr (abfd)->aux_header_size
+= sizeof (struct som_exec_auxhdr);
exec_header = obj_som_exec_hdr (abfd);
exec_header->som_auxhdr.type = EXEC_AUX_ID;
exec_header->som_auxhdr.length = 40;
}
if (obj_som_version_hdr (abfd) != NULL)
{
bfd_size_type len;
if (bfd_seek (abfd, (file_ptr) current_offset, SEEK_SET) != 0)
return FALSE;
len = sizeof (struct aux_id) + sizeof (unsigned int);
obj_som_file_hdr (abfd)->aux_header_size += len;
current_offset += len;
if (bfd_bwrite ((void *) obj_som_version_hdr (abfd), len, abfd) != len)
return FALSE;
len = obj_som_version_hdr (abfd)->header_id.length - sizeof (int);
obj_som_file_hdr (abfd)->aux_header_size += len;
current_offset += len;
if (bfd_bwrite ((void *) obj_som_version_hdr (abfd)->user_string, len, abfd)
!= len)
return FALSE;
}
if (obj_som_copyright_hdr (abfd) != NULL)
{
bfd_size_type len;
if (bfd_seek (abfd, (file_ptr) current_offset, SEEK_SET) != 0)
return FALSE;
len = sizeof (struct aux_id) + sizeof (unsigned int);
obj_som_file_hdr (abfd)->aux_header_size += len;
current_offset += len;
if (bfd_bwrite ((void *) obj_som_copyright_hdr (abfd), len, abfd) != len)
return FALSE;
len = obj_som_copyright_hdr (abfd)->header_id.length - sizeof (int);
obj_som_file_hdr (abfd)->aux_header_size += len;
current_offset += len;
if (bfd_bwrite ((void *) obj_som_copyright_hdr (abfd)->copyright, len, abfd)
!= len)
return FALSE;
}
obj_som_file_hdr (abfd)->init_array_location = current_offset;
obj_som_file_hdr (abfd)->init_array_total = 0;
num_spaces = som_count_spaces (abfd);
obj_som_file_hdr (abfd)->space_location = current_offset;
obj_som_file_hdr (abfd)->space_total = num_spaces;
current_offset += num_spaces * sizeof (struct space_dictionary_record);
num_subspaces = som_count_subspaces (abfd);
obj_som_file_hdr (abfd)->subspace_location = current_offset;
obj_som_file_hdr (abfd)->subspace_total = num_subspaces;
current_offset
+= num_subspaces * sizeof (struct som_subspace_dictionary_record);
if (current_offset % 4)
current_offset += (4 - (current_offset % 4));
obj_som_file_hdr (abfd)->space_strings_location = current_offset;
if (! som_write_space_strings (abfd, current_offset, &strings_size))
return FALSE;
obj_som_file_hdr (abfd)->space_strings_size = strings_size;
current_offset += strings_size;
obj_som_file_hdr (abfd)->compiler_location = current_offset;
obj_som_file_hdr (abfd)->compiler_total = 0;
if (obj_som_compilation_unit (abfd))
{
obj_som_file_hdr (abfd)->compiler_total = 1;
current_offset += COMPUNITSZ;
}
section = abfd->sections;
for (i = 0; i < num_spaces; i++)
{
asection *subsection;
int first_subspace;
unsigned int subspace_offset = 0;
while (!som_is_space (section))
section = section->next;
first_subspace = 1;
for (subsection = abfd->sections;
subsection != NULL;
subsection = subsection->next)
{
if (!som_is_subspace (subsection)
|| !som_is_container (section, subsection)
|| (subsection->flags & SEC_ALLOC) == 0)
continue;
if (first_subspace
&& (abfd->flags & (EXEC_P | DYNAMIC)))
{
if (abfd->flags & (D_PAGED | DYNAMIC)
|| (subsection->flags & SEC_CODE)
|| ((abfd->flags & WP_TEXT)
&& (subsection->flags & SEC_DATA)))
current_offset = SOM_ALIGN (current_offset, PA_PAGESIZE);
if (subsection->flags & SEC_CODE && exec_header->exec_tfile == 0)
{
exec_header->exec_tmem = section->vma;
exec_header->exec_tfile = current_offset;
}
if (subsection->flags & SEC_DATA && exec_header->exec_dfile == 0)
{
exec_header->exec_dmem = section->vma;
exec_header->exec_dfile = current_offset;
}
subspace_offset = subsection->vma;
first_subspace = 0;
}
else if (abfd->flags & (EXEC_P | DYNAMIC))
{
current_offset += subsection->vma - subspace_offset;
if (subsection->flags & SEC_CODE)
exec_header->exec_tsize += subsection->vma - subspace_offset;
else
exec_header->exec_dsize += subsection->vma - subspace_offset;
subspace_offset += subsection->vma - subspace_offset;
}
subsection->target_index = total_subspaces++;
if (subsection->flags & SEC_LOAD)
{
if (abfd->flags & (EXEC_P | DYNAMIC)
&& subsection->flags & SEC_CODE)
exec_header->exec_tsize += subsection->size;
else if (abfd->flags & (EXEC_P | DYNAMIC)
&& subsection->flags & SEC_DATA)
exec_header->exec_dsize += subsection->size;
som_section_data (subsection)->subspace_dict->file_loc_init_value
= current_offset;
subsection->filepos = current_offset;
current_offset += subsection->size;
subspace_offset += subsection->size;
}
else
{
if (abfd->flags & (EXEC_P | DYNAMIC))
exec_header->exec_bsize += subsection->size;
som_section_data (subsection)->subspace_dict->file_loc_init_value
= 0;
som_section_data (subsection)->subspace_dict->
initialization_length = 0;
}
}
section = section->next;
}
if (abfd->flags & (EXEC_P | DYNAMIC))
current_offset = SOM_ALIGN (current_offset, PA_PAGESIZE);
obj_som_file_hdr (abfd)->unloadable_sp_location = current_offset;
section = abfd->sections;
for (i = 0; i < num_spaces; i++)
{
asection *subsection;
while (!som_is_space (section))
section = section->next;
if (abfd->flags & (EXEC_P | DYNAMIC))
current_offset = SOM_ALIGN (current_offset, PA_PAGESIZE);
for (subsection = abfd->sections;
subsection != NULL;
subsection = subsection->next)
{
if (!som_is_subspace (subsection)
|| !som_is_container (section, subsection)
|| (subsection->flags & SEC_ALLOC) != 0)
continue;
subsection->target_index = total_subspaces++;
if ((subsection->flags & SEC_LOAD) == 0)
{
som_section_data (subsection)->subspace_dict->file_loc_init_value
= current_offset;
subsection->filepos = current_offset;
current_offset += subsection->size;
}
else
{
som_section_data (subsection)->subspace_dict->file_loc_init_value
= 0;
som_section_data (subsection)->subspace_dict->
initialization_length = subsection->size;
}
}
section = section->next;
}
if (abfd->flags & (EXEC_P | DYNAMIC))
current_offset = SOM_ALIGN (current_offset, PA_PAGESIZE);
if (bfd_seek (abfd, (file_ptr) current_offset - 1, SEEK_SET) != 0)
return FALSE;
if (bfd_bwrite ((void *) "", (bfd_size_type) 1, abfd) != 1)
return FALSE;
obj_som_file_hdr (abfd)->unloadable_sp_size
= current_offset - obj_som_file_hdr (abfd)->unloadable_sp_location;
obj_som_file_hdr (abfd)->loader_fixup_location = 0;
obj_som_file_hdr (abfd)->loader_fixup_total = 0;
obj_som_file_hdr (abfd)->som_length = current_offset;
return TRUE;
}
static bfd_boolean
som_finish_writing (bfd *abfd)
{
int num_spaces = som_count_spaces (abfd);
asymbol **syms = bfd_get_outsymbols (abfd);
int i, num_syms;
int subspace_index = 0;
file_ptr location;
asection *section;
unsigned long current_offset;
unsigned int strings_size, total_reloc_size;
bfd_size_type amt;
if (obj_som_exec_data (abfd)
&& obj_som_exec_data (abfd)->version_id)
obj_som_file_hdr (abfd)->version_id = obj_som_exec_data (abfd)->version_id;
else
obj_som_file_hdr (abfd)->version_id = NEW_VERSION_ID;
current_offset = obj_som_file_hdr (abfd)->som_length;
if (current_offset % 4)
current_offset += (4 - (current_offset % 4));
num_syms = bfd_get_symcount (abfd);
obj_som_file_hdr (abfd)->symbol_location = current_offset;
obj_som_file_hdr (abfd)->symbol_total = num_syms;
current_offset += num_syms * sizeof (struct symbol_dictionary_record);
if (current_offset % 4)
current_offset += (4 - (current_offset % 4));
obj_som_file_hdr (abfd)->symbol_strings_location = current_offset;
if (! som_write_symbol_strings (abfd, current_offset, syms,
num_syms, &strings_size,
obj_som_compilation_unit (abfd)))
return FALSE;
obj_som_file_hdr (abfd)->symbol_strings_size = strings_size;
current_offset += strings_size;
som_prep_for_fixups (abfd,
bfd_get_outsymbols (abfd),
bfd_get_symcount (abfd));
if (current_offset % 4)
current_offset += (4 - (current_offset % 4));
obj_som_file_hdr (abfd)->fixup_request_location = current_offset;
if (! som_write_fixups (abfd, current_offset, &total_reloc_size))
return FALSE;
obj_som_file_hdr (abfd)->fixup_request_total = total_reloc_size;
obj_som_file_hdr (abfd)->som_length = current_offset + total_reloc_size;
if (! som_build_and_write_symbol_table (abfd))
return FALSE;
location = obj_som_file_hdr (abfd)->subspace_location;
if (bfd_seek (abfd, location, SEEK_SET) != 0)
return FALSE;
section = abfd->sections;
for (i = 0; i < num_spaces; i++)
{
asection *subsection;
while (!som_is_space (section))
section = section->next;
for (subsection = abfd->sections;
subsection != NULL;
subsection = subsection->next)
{
if (!som_is_subspace (subsection)
|| !som_is_container (section, subsection)
|| (subsection->flags & SEC_ALLOC) == 0)
continue;
if (som_section_data (section)->space_dict->subspace_quantity == 0)
{
som_section_data (section)->space_dict->is_loadable = 1;
som_section_data (section)->space_dict->subspace_index
= subspace_index;
}
subspace_index++;
som_section_data (section)->space_dict->subspace_quantity++;
som_section_data (subsection)->subspace_dict->space_index = i;
amt = sizeof (struct som_subspace_dictionary_record);
if (bfd_bwrite ((void *) som_section_data (subsection)->subspace_dict,
amt, abfd) != amt)
return FALSE;
}
section = section->next;
}
section = abfd->sections;
for (i = 0; i < num_spaces; i++)
{
asection *subsection;
while (!som_is_space (section))
section = section->next;
for (subsection = abfd->sections;
subsection != NULL;
subsection = subsection->next)
{
if (!som_is_subspace (subsection)
|| !som_is_container (section, subsection)
|| (subsection->flags & SEC_ALLOC) != 0)
continue;
if (som_section_data (section)->space_dict->subspace_quantity == 0)
{
som_section_data (section)->space_dict->is_loadable = 0;
som_section_data (section)->space_dict->subspace_index
= subspace_index;
}
som_section_data (section)->space_dict->subspace_quantity++;
subspace_index++;
som_section_data (subsection)->subspace_dict->space_index = i;
amt = sizeof (struct som_subspace_dictionary_record);
if (bfd_bwrite ((void *) som_section_data (subsection)->subspace_dict,
amt, abfd) != amt)
return FALSE;
}
section = section->next;
}
location = obj_som_file_hdr (abfd)->space_location;
if (bfd_seek (abfd, location, SEEK_SET) != 0)
return FALSE;
section = abfd->sections;
for (i = 0; i < num_spaces; i++)
{
while (!som_is_space (section))
section = section->next;
amt = sizeof (struct space_dictionary_record);
if (bfd_bwrite ((void *) som_section_data (section)->space_dict,
amt, abfd) != amt)
return FALSE;
section = section->next;
}
if (obj_som_compilation_unit (abfd))
{
location = obj_som_file_hdr (abfd)->compiler_location;
if (bfd_seek (abfd, location, SEEK_SET) != 0)
return FALSE;
amt = COMPUNITSZ;
if (bfd_bwrite ((void *) obj_som_compilation_unit (abfd), amt, abfd) != amt)
return FALSE;
}
if (abfd->flags & (EXEC_P | DYNAMIC))
obj_som_file_hdr (abfd)->system_id = obj_som_exec_data (abfd)->system_id;
else if (bfd_get_mach (abfd) == pa20)
obj_som_file_hdr (abfd)->system_id = CPU_PA_RISC2_0;
else if (bfd_get_mach (abfd) == pa11)
obj_som_file_hdr (abfd)->system_id = CPU_PA_RISC1_1;
else
obj_som_file_hdr (abfd)->system_id = CPU_PA_RISC1_0;
obj_som_file_hdr (abfd)->checksum = som_compute_checksum (abfd);
if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
return FALSE;
amt = sizeof (struct header);
if (bfd_bwrite ((void *) obj_som_file_hdr (abfd), amt, abfd) != amt)
return FALSE;
if (abfd->flags & (EXEC_P | DYNAMIC))
{
long tmp, som_length;
struct som_exec_auxhdr *exec_header;
exec_header = obj_som_exec_hdr (abfd);
exec_header->exec_entry = bfd_get_start_address (abfd);
exec_header->exec_flags = obj_som_exec_data (abfd)->exec_flags;
tmp = exec_header->exec_dsize;
tmp = SOM_ALIGN (tmp, PA_PAGESIZE);
exec_header->exec_bsize -= (tmp - exec_header->exec_dsize);
if (exec_header->exec_bsize < 0)
exec_header->exec_bsize = 0;
exec_header->exec_dsize = tmp;
som_length = obj_som_file_hdr (abfd)->som_length;
if (exec_header->exec_tfile + exec_header->exec_tsize > som_length
|| exec_header->exec_dfile + exec_header->exec_dsize > som_length)
{
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
if (bfd_seek (abfd, obj_som_file_hdr (abfd)->aux_header_location,
SEEK_SET) != 0)
return FALSE;
amt = AUX_HDR_SIZE;
if (bfd_bwrite ((void *) exec_header, amt, abfd) != amt)
return FALSE;
}
return TRUE;
}
static unsigned long
som_compute_checksum (bfd *abfd)
{
unsigned long checksum, count, i;
unsigned long *buffer = (unsigned long *) obj_som_file_hdr (abfd);
checksum = 0;
count = sizeof (struct header) / sizeof (unsigned long);
for (i = 0; i < count; i++)
checksum ^= *(buffer + i);
return checksum;
}
static void
som_bfd_derive_misc_symbol_info (bfd *abfd ATTRIBUTE_UNUSED,
asymbol *sym,
struct som_misc_symbol_info *info)
{
memset (info, 0, sizeof (struct som_misc_symbol_info));
if (sym->flags & BSF_SECTION_SYM)
info->symbol_type = ST_DATA;
else
{
if (bfd_is_com_section (sym->section))
{
info->symbol_type = ST_STORAGE;
info->symbol_scope = SS_UNSAT;
}
else if ((som_symbol_data (sym)->som_type == SYMBOL_TYPE_UNKNOWN
|| som_symbol_data (sym)->som_type == SYMBOL_TYPE_CODE)
&& bfd_is_und_section (sym->section)
&& sym->flags & BSF_FUNCTION)
info->symbol_type = ST_CODE;
else if (som_symbol_data (sym)->som_type == SYMBOL_TYPE_ENTRY
|| (som_symbol_data (sym)->som_type == SYMBOL_TYPE_CODE
&& (sym->flags & BSF_FUNCTION))
|| (som_symbol_data (sym)->som_type == SYMBOL_TYPE_UNKNOWN
&& (sym->flags & BSF_FUNCTION)))
{
info->symbol_type = ST_ENTRY;
info->arg_reloc = som_symbol_data (sym)->tc_data.ap.hppa_arg_reloc;
info->priv_level= som_symbol_data (sym)->tc_data.ap.hppa_priv_level;
}
else if (som_symbol_data (sym)->som_type == SYMBOL_TYPE_UNKNOWN)
{
if (sym->section->flags & SEC_CODE)
info->symbol_type = ST_CODE;
else
info->symbol_type = ST_DATA;
}
else if (som_symbol_data (sym)->som_type == SYMBOL_TYPE_ABSOLUTE)
info->symbol_type = ST_ABSOLUTE;
else if (som_symbol_data (sym)->som_type == SYMBOL_TYPE_CODE)
info->symbol_type = ST_CODE;
else if (som_symbol_data (sym)->som_type == SYMBOL_TYPE_DATA)
info->symbol_type = ST_DATA;
else if (som_symbol_data (sym)->som_type == SYMBOL_TYPE_MILLICODE)
info->symbol_type = ST_MILLICODE;
else if (som_symbol_data (sym)->som_type == SYMBOL_TYPE_PLABEL)
info->symbol_type = ST_PLABEL;
else if (som_symbol_data (sym)->som_type == SYMBOL_TYPE_PRI_PROG)
info->symbol_type = ST_PRI_PROG;
else if (som_symbol_data (sym)->som_type == SYMBOL_TYPE_SEC_PROG)
info->symbol_type = ST_SEC_PROG;
}
if (bfd_is_com_section (sym->section))
;
else if (bfd_is_und_section (sym->section))
info->symbol_scope = SS_UNSAT;
else if (sym->flags & (BSF_EXPORT | BSF_WEAK))
info->symbol_scope = SS_UNIVERSAL;
else
info->symbol_scope = SS_LOCAL;
if (bfd_is_com_section (sym->section)
|| bfd_is_und_section (sym->section)
|| bfd_is_abs_section (sym->section))
info->symbol_info = 0;
else
info->symbol_info = sym->section->target_index;
info->symbol_value = sym->value + sym->section->vma;
if (sym->flags & BSF_WEAK)
info->secondary_def = TRUE;
else
info->secondary_def = FALSE;
if (som_section_data (sym->section)
&& som_section_data (sym->section)->subspace_dict
&& info->symbol_scope == SS_UNIVERSAL
&& (info->symbol_type == ST_ENTRY
|| info->symbol_type == ST_CODE
|| info->symbol_type == ST_DATA))
{
info->is_comdat
= som_section_data (sym->section)->subspace_dict->is_comdat;
info->is_common
= som_section_data (sym->section)->subspace_dict->is_common;
info->dup_common
= som_section_data (sym->section)->subspace_dict->dup_common;
}
}
static bfd_boolean
som_build_and_write_symbol_table (bfd *abfd)
{
unsigned int num_syms = bfd_get_symcount (abfd);
file_ptr symtab_location = obj_som_file_hdr (abfd)->symbol_location;
asymbol **bfd_syms = obj_som_sorted_syms (abfd);
struct symbol_dictionary_record *som_symtab = NULL;
unsigned int i;
bfd_size_type symtab_size;
symtab_size = num_syms;
symtab_size *= sizeof (struct symbol_dictionary_record);
som_symtab = bfd_zmalloc (symtab_size);
if (som_symtab == NULL && symtab_size != 0)
goto error_return;
for (i = 0; i < num_syms; i++)
{
struct som_misc_symbol_info info;
som_symtab[i].name.n_strx = som_symbol_data(bfd_syms[i])->stringtab_offset;
som_bfd_derive_misc_symbol_info (abfd, bfd_syms[i], &info);
som_symtab[i].symbol_type = info.symbol_type;
som_symtab[i].symbol_scope = info.symbol_scope;
som_symtab[i].arg_reloc = info.arg_reloc;
som_symtab[i].symbol_info = info.symbol_info;
som_symtab[i].xleast = 3;
som_symtab[i].symbol_value = info.symbol_value | info.priv_level;
som_symtab[i].secondary_def = info.secondary_def;
som_symtab[i].is_comdat = info.is_comdat;
som_symtab[i].is_common = info.is_common;
som_symtab[i].dup_common = info.dup_common;
}
if (bfd_seek (abfd, symtab_location, SEEK_SET) != 0)
return FALSE;
if (bfd_bwrite ((void *) som_symtab, symtab_size, abfd) != symtab_size)
goto error_return;
if (som_symtab != NULL)
free (som_symtab);
return TRUE;
error_return:
if (som_symtab != NULL)
free (som_symtab);
return FALSE;
}
static bfd_boolean
som_write_object_contents (bfd *abfd)
{
if (! abfd->output_has_begun)
{
som_prep_headers (abfd);
abfd->output_has_begun = TRUE;
som_begin_writing (abfd);
}
return som_finish_writing (abfd);
}
static bfd_boolean
som_slurp_string_table (bfd *abfd)
{
char *stringtab;
bfd_size_type amt;
if (obj_som_stringtab (abfd) != NULL)
return TRUE;
if (obj_som_stringtab_size (abfd) == 0)
{
bfd_set_error (bfd_error_no_symbols);
return FALSE;
}
amt = obj_som_stringtab_size (abfd);
stringtab = bfd_zmalloc (amt);
if (stringtab == NULL)
return FALSE;
if (bfd_seek (abfd, obj_som_str_filepos (abfd), SEEK_SET) != 0)
return FALSE;
if (bfd_bread (stringtab, amt, abfd) != amt)
return FALSE;
obj_som_stringtab (abfd) = stringtab;
return TRUE;
}
static long
som_get_symtab_upper_bound (bfd *abfd)
{
if (!som_slurp_symbol_table (abfd))
return -1;
return (bfd_get_symcount (abfd) + 1) * sizeof (asymbol *);
}
static asection *
bfd_section_from_som_symbol (bfd *abfd, struct symbol_dictionary_record *symbol)
{
asection *section;
if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0
|| (symbol->symbol_type != ST_ENTRY
&& symbol->symbol_type != ST_PRI_PROG
&& symbol->symbol_type != ST_SEC_PROG
&& symbol->symbol_type != ST_MILLICODE))
{
int index = symbol->symbol_info;
for (section = abfd->sections; section != NULL; section = section->next)
if (section->target_index == index && som_is_subspace (section))
return section;
}
else
{
unsigned int value = symbol->symbol_value;
for (section = abfd->sections; section; section = section->next)
if (value >= section->vma
&& value <= section->vma + section->size
&& som_is_subspace (section))
return section;
}
return bfd_abs_section_ptr;
}
static unsigned int
som_slurp_symbol_table (bfd *abfd)
{
int symbol_count = bfd_get_symcount (abfd);
int symsize = sizeof (struct symbol_dictionary_record);
char *stringtab;
struct symbol_dictionary_record *buf = NULL, *bufp, *endbufp;
som_symbol_type *sym, *symbase;
bfd_size_type amt;
if (obj_som_symtab (abfd) != NULL)
goto successful_return;
if (symbol_count == 0)
goto successful_return;
if (!som_slurp_string_table (abfd))
goto error_return;
stringtab = obj_som_stringtab (abfd);
amt = symbol_count;
amt *= sizeof (som_symbol_type);
symbase = bfd_zmalloc (amt);
if (symbase == NULL)
goto error_return;
amt = symbol_count;
amt *= symsize;
buf = bfd_malloc (amt);
if (buf == NULL && amt != 0)
goto error_return;
if (bfd_seek (abfd, obj_som_sym_filepos (abfd), SEEK_SET) != 0)
goto error_return;
if (bfd_bread (buf, amt, abfd) != amt)
goto error_return;
endbufp = buf + symbol_count;
for (bufp = buf, sym = symbase; bufp < endbufp; ++bufp)
{
if (bufp->symbol_type == ST_SYM_EXT
|| bufp->symbol_type == ST_ARG_EXT)
continue;
if (bufp->symbol_type == ST_NULL)
som_symbol_data (sym)->som_type = SYMBOL_TYPE_UNKNOWN;
else if (bufp->symbol_type == ST_ABSOLUTE)
som_symbol_data (sym)->som_type = SYMBOL_TYPE_ABSOLUTE;
else if (bufp->symbol_type == ST_DATA)
som_symbol_data (sym)->som_type = SYMBOL_TYPE_DATA;
else if (bufp->symbol_type == ST_CODE)
som_symbol_data (sym)->som_type = SYMBOL_TYPE_CODE;
else if (bufp->symbol_type == ST_PRI_PROG)
som_symbol_data (sym)->som_type = SYMBOL_TYPE_PRI_PROG;
else if (bufp->symbol_type == ST_SEC_PROG)
som_symbol_data (sym)->som_type = SYMBOL_TYPE_SEC_PROG;
else if (bufp->symbol_type == ST_ENTRY)
som_symbol_data (sym)->som_type = SYMBOL_TYPE_ENTRY;
else if (bufp->symbol_type == ST_MILLICODE)
som_symbol_data (sym)->som_type = SYMBOL_TYPE_MILLICODE;
else if (bufp->symbol_type == ST_PLABEL)
som_symbol_data (sym)->som_type = SYMBOL_TYPE_PLABEL;
else
som_symbol_data (sym)->som_type = SYMBOL_TYPE_UNKNOWN;
som_symbol_data (sym)->tc_data.ap.hppa_arg_reloc = bufp->arg_reloc;
sym->symbol.the_bfd = abfd;
sym->symbol.name = bufp->name.n_strx + stringtab;
sym->symbol.value = bufp->symbol_value;
sym->symbol.section = 0;
sym->symbol.flags = 0;
switch (bufp->symbol_type)
{
case ST_ENTRY:
case ST_MILLICODE:
sym->symbol.flags |= BSF_FUNCTION;
som_symbol_data (sym)->tc_data.ap.hppa_priv_level =
sym->symbol.value & 0x3;
sym->symbol.value &= ~0x3;
break;
case ST_STUB:
case ST_CODE:
case ST_PRI_PROG:
case ST_SEC_PROG:
som_symbol_data (sym)->tc_data.ap.hppa_priv_level =
sym->symbol.value & 0x3;
sym->symbol.value &= ~0x3;
if (bufp->symbol_scope == SS_UNSAT)
sym->symbol.flags |= BSF_FUNCTION;
default:
break;
}
switch (bufp->symbol_scope)
{
case SS_EXTERNAL:
if (bufp->symbol_type != ST_STORAGE)
sym->symbol.section = bfd_und_section_ptr;
else
sym->symbol.section = bfd_com_section_ptr;
sym->symbol.flags |= (BSF_EXPORT | BSF_GLOBAL);
break;
case SS_UNSAT:
if (bufp->symbol_type != ST_STORAGE)
sym->symbol.section = bfd_und_section_ptr;
else
sym->symbol.section = bfd_com_section_ptr;
break;
case SS_UNIVERSAL:
sym->symbol.flags |= (BSF_EXPORT | BSF_GLOBAL);
sym->symbol.section = bfd_section_from_som_symbol (abfd, bufp);
sym->symbol.value -= sym->symbol.section->vma;
break;
case SS_LOCAL:
sym->symbol.flags |= BSF_LOCAL;
sym->symbol.section = bfd_section_from_som_symbol (abfd, bufp);
sym->symbol.value -= sym->symbol.section->vma;
break;
}
if (bufp->secondary_def)
sym->symbol.flags |= BSF_WEAK;
if (sym->symbol.name[0] == '$'
&& sym->symbol.name[strlen (sym->symbol.name) - 1] == '$'
&& !strcmp (sym->symbol.name, sym->symbol.section->name))
sym->symbol.flags |= BSF_SECTION_SYM;
else if (!strncmp (sym->symbol.name, "L$0\002", 4))
{
sym->symbol.flags |= BSF_SECTION_SYM;
sym->symbol.name = sym->symbol.section->name;
}
else if (!strncmp (sym->symbol.name, "L$0\001", 4))
sym->symbol.flags |= BSF_DEBUGGING;
sym++;
}
bfd_get_symcount (abfd) = sym - symbase;
obj_som_symtab (abfd) = symbase;
successful_return:
if (buf != NULL)
free (buf);
return (TRUE);
error_return:
if (buf != NULL)
free (buf);
return FALSE;
}
static long
som_canonicalize_symtab (bfd *abfd, asymbol **location)
{
int i;
som_symbol_type *symbase;
if (!som_slurp_symbol_table (abfd))
return -1;
i = bfd_get_symcount (abfd);
symbase = obj_som_symtab (abfd);
for (; i > 0; i--, location++, symbase++)
*location = &symbase->symbol;
*location = 0;
return (bfd_get_symcount (abfd));
}
static asymbol *
som_make_empty_symbol (bfd *abfd)
{
bfd_size_type amt = sizeof (som_symbol_type);
som_symbol_type *new = bfd_zalloc (abfd, amt);
if (new == NULL)
return NULL;
new->symbol.the_bfd = abfd;
return &new->symbol;
}
static void
som_print_symbol (bfd *abfd,
void *afile,
asymbol *symbol,
bfd_print_symbol_type how)
{
FILE *file = (FILE *) afile;
switch (how)
{
case bfd_print_symbol_name:
fprintf (file, "%s", symbol->name);
break;
case bfd_print_symbol_more:
fprintf (file, "som ");
fprintf_vma (file, symbol->value);
fprintf (file, " %lx", (long) symbol->flags);
break;
case bfd_print_symbol_all:
{
const char *section_name;
section_name = symbol->section ? symbol->section->name : "(*none*)";
bfd_print_symbol_vandf (abfd, (void *) file, symbol);
fprintf (file, " %s\t%s", section_name, symbol->name);
break;
}
}
}
static bfd_boolean
som_bfd_is_local_label_name (bfd *abfd ATTRIBUTE_UNUSED,
const char *name)
{
return name[0] == 'L' && name[1] == '$';
}
static unsigned int
som_set_reloc_info (unsigned char *fixup,
unsigned int end,
arelent *internal_relocs,
asection *section,
asymbol **symbols,
bfd_boolean just_count)
{
unsigned int op, varname, deallocate_contents = 0;
unsigned char *end_fixups = &fixup[end];
const struct fixup_format *fp;
const char *cp;
unsigned char *save_fixup;
int variables[26], stack[20], c, v, count, prev_fixup, *sp, saved_unwind_bits;
const int *subop;
arelent *rptr = internal_relocs;
unsigned int offset = 0;
#define var(c) variables[(c) - 'A']
#define push(v) (*sp++ = (v))
#define pop() (*--sp)
#define emptystack() (sp == stack)
som_initialize_reloc_queue (reloc_queue);
memset (variables, 0, sizeof (variables));
memset (stack, 0, sizeof (stack));
count = 0;
prev_fixup = 0;
saved_unwind_bits = 0;
sp = stack;
while (fixup < end_fixups)
{
save_fixup = fixup;
op = *fixup++;
fp = &som_fixup_formats[op];
if (*fp->format == 'P')
{
fixup = reloc_queue[fp->D].reloc;
som_reloc_queue_fix (reloc_queue, fp->D);
prev_fixup = 1;
op = *fixup++;
fp = &som_fixup_formats[op];
}
if (! just_count
&& som_hppa_howto_table[op].type != R_NO_RELOCATION
&& som_hppa_howto_table[op].type != R_DATA_OVERRIDE)
{
rptr->address = offset;
rptr->howto = &som_hppa_howto_table[op];
rptr->addend = 0;
rptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
}
var ('L') = 0;
var ('D') = fp->D;
var ('U') = saved_unwind_bits;
cp = fp->format;
while (*cp)
{
varname = *cp++;
do
{
c = *cp++;
if (ISUPPER (c))
push (var (c));
else if (ISLOWER (c))
{
int bits = (c - 'a') * 8;
for (v = 0; c > 'a'; --c)
v = (v << 8) | *fixup++;
if (varname == 'V')
v = sign_extend (v, bits);
push (v);
}
else if (ISDIGIT (c))
{
v = c - '0';
while (ISDIGIT (*cp))
v = (v * 10) + (*cp++ - '0');
push (v);
}
else
switch (c)
{
case '+':
v = pop ();
v += pop ();
push (v);
break;
case '*':
v = pop ();
v *= pop ();
push (v);
break;
case '<':
v = pop ();
v = pop () << v;
push (v);
break;
default:
abort ();
}
}
while (*cp && *cp != '=');
cp++;
c = pop ();
var (varname) = c;
switch (varname)
{
case 'L':
offset += c;
break;
case 'S':
if (! just_count)
rptr->sym_ptr_ptr = &symbols[c];
break;
case 'R':
if (! just_count)
{
unsigned int tmp = var ('R');
rptr->addend = 0;
if ((som_hppa_howto_table[op].type == R_PCREL_CALL
&& R_PCREL_CALL + 10 > op)
|| (som_hppa_howto_table[op].type == R_ABS_CALL
&& R_ABS_CALL + 10 > op))
{
if (tmp > 4)
{
tmp -= 5;
rptr->addend |= 1;
}
if (tmp == 4)
rptr->addend |= 1 << 8 | 1 << 6 | 1 << 4 | 1 << 2;
else if (tmp == 3)
rptr->addend |= 1 << 8 | 1 << 6 | 1 << 4;
else if (tmp == 2)
rptr->addend |= 1 << 8 | 1 << 6;
else if (tmp == 1)
rptr->addend |= 1 << 8;
}
else
{
unsigned int tmp1, tmp2;
rptr->addend = tmp & 0x3;
tmp >>= 2;
tmp1 = tmp / 10;
tmp -= tmp1 * 10;
if (tmp1 == 9)
rptr->addend += (0xe << 6);
else
{
tmp2 = tmp1 / 3;
tmp1 -= tmp2 * 3;
rptr->addend += (tmp2 << 8) + (tmp1 << 6);
}
if (tmp == 9)
rptr->addend += (0xe << 2);
else
{
tmp2 = tmp / 3;
tmp -= tmp2 * 3;
rptr->addend += (tmp2 << 4) + (tmp << 2);
}
}
rptr->addend = HPPA_R_ADDEND (rptr->addend, 0);
}
break;
case 'O':
switch (op)
{
case R_COMP1:
subop = comp1_opcodes;
break;
case R_COMP2:
subop = comp2_opcodes;
break;
case R_COMP3:
subop = comp3_opcodes;
break;
default:
abort ();
}
while (*subop <= (unsigned char) c)
++subop;
--subop;
break;
case 'U':
saved_unwind_bits = var ('U');
break;
default:
break;
}
}
if (prev_fixup)
{
fixup = save_fixup + 1;
prev_fixup = 0;
}
else if (fixup > save_fixup + 1)
som_reloc_queue_insert (save_fixup, fixup - save_fixup, reloc_queue);
if (som_hppa_howto_table[op].type != R_DATA_OVERRIDE
&& som_hppa_howto_table[op].type != R_NO_RELOCATION)
{
if (! just_count)
{
if (som_hppa_howto_table[op].type == R_ENTRY)
rptr->addend = var ('T');
else if (som_hppa_howto_table[op].type == R_EXIT)
rptr->addend = var ('U');
else if (som_hppa_howto_table[op].type == R_PCREL_CALL
|| som_hppa_howto_table[op].type == R_ABS_CALL)
;
else if (som_hppa_howto_table[op].type == R_DATA_ONE_SYMBOL)
{
rptr->addend = var ('V');
if (rptr->addend == 0 && !section->contents)
{
bfd_byte *contents;
if (!bfd_malloc_and_get_section (section->owner, section,
&contents))
{
if (contents != NULL)
free (contents);
return (unsigned) -1;
}
section->contents = contents;
deallocate_contents = 1;
}
else if (rptr->addend == 0)
rptr->addend = bfd_get_32 (section->owner,
(section->contents
+ offset - var ('L')));
}
else
rptr->addend = var ('V');
rptr++;
}
count++;
memset (variables, 0, sizeof (variables));
memset (stack, 0, sizeof (stack));
}
}
if (deallocate_contents)
free (section->contents);
return count;
#undef var
#undef push
#undef pop
#undef emptystack
}
static bfd_boolean
som_slurp_reloc_table (bfd *abfd,
asection *section,
asymbol **symbols,
bfd_boolean just_count)
{
unsigned char *external_relocs;
unsigned int fixup_stream_size;
arelent *internal_relocs;
unsigned int num_relocs;
bfd_size_type amt;
fixup_stream_size = som_section_data (section)->reloc_size;
if (section->reloc_count == 0)
return TRUE;
if (section->reloc_count == (unsigned) -1)
{
amt = fixup_stream_size;
external_relocs = bfd_malloc (amt);
if (external_relocs == NULL)
return FALSE;
if (bfd_seek (abfd,
obj_som_reloc_filepos (abfd) + section->rel_filepos,
SEEK_SET)
!= 0)
return FALSE;
if (bfd_bread (external_relocs, amt, abfd) != amt)
return FALSE;
section->reloc_count = som_set_reloc_info (external_relocs,
fixup_stream_size,
NULL, NULL, NULL, TRUE);
som_section_data (section)->reloc_stream = external_relocs;
}
if (just_count)
return TRUE;
num_relocs = section->reloc_count;
external_relocs = som_section_data (section)->reloc_stream;
if (section->relocation != NULL)
return TRUE;
amt = num_relocs;
amt *= sizeof (arelent);
internal_relocs = bfd_zalloc (abfd, (amt));
if (internal_relocs == NULL)
return FALSE;
som_set_reloc_info (external_relocs, fixup_stream_size,
internal_relocs, section, symbols, FALSE);
free (external_relocs);
som_section_data (section)->reloc_stream = NULL;
section->relocation = internal_relocs;
return TRUE;
}
static long
som_get_reloc_upper_bound (bfd *abfd, sec_ptr asect)
{
if (asect->flags & SEC_RELOC)
{
if (! som_slurp_reloc_table (abfd, asect, NULL, TRUE))
return -1;
return (asect->reloc_count + 1) * sizeof (arelent *);
}
return 0;
}
static long
som_canonicalize_reloc (bfd *abfd,
sec_ptr section,
arelent **relptr,
asymbol **symbols)
{
arelent *tblptr;
int count;
if (! som_slurp_reloc_table (abfd, section, symbols, FALSE))
return -1;
count = section->reloc_count;
tblptr = section->relocation;
while (count--)
*relptr++ = tblptr++;
*relptr = NULL;
return section->reloc_count;
}
extern const bfd_target som_vec;
static bfd_boolean
som_new_section_hook (bfd *abfd, asection *newsect)
{
bfd_size_type amt = sizeof (struct som_section_data_struct);
newsect->used_by_bfd = bfd_zalloc (abfd, amt);
if (!newsect->used_by_bfd)
return FALSE;
newsect->alignment_power = 3;
return TRUE;
}
static bfd_boolean
som_bfd_copy_private_symbol_data (bfd *ibfd,
asymbol *isymbol,
bfd *obfd,
asymbol *osymbol)
{
struct som_symbol *input_symbol = (struct som_symbol *) isymbol;
struct som_symbol *output_symbol = (struct som_symbol *) osymbol;
if (ibfd->xvec->flavour != bfd_target_som_flavour
|| obfd->xvec->flavour != bfd_target_som_flavour)
return FALSE;
output_symbol->tc_data.ap.hppa_arg_reloc =
input_symbol->tc_data.ap.hppa_arg_reloc;
return TRUE;
}
static bfd_boolean
som_bfd_copy_private_section_data (bfd *ibfd,
asection *isection,
bfd *obfd,
asection *osection)
{
bfd_size_type amt;
if (ibfd->xvec->flavour != bfd_target_som_flavour
|| obfd->xvec->flavour != bfd_target_som_flavour
|| (!som_is_space (isection) && !som_is_subspace (isection)))
return TRUE;
amt = sizeof (struct som_copyable_section_data_struct);
som_section_data (osection)->copy_data = bfd_zalloc (obfd, amt);
if (som_section_data (osection)->copy_data == NULL)
return FALSE;
memcpy (som_section_data (osection)->copy_data,
som_section_data (isection)->copy_data,
sizeof (struct som_copyable_section_data_struct));
if (som_section_data (osection)->copy_data->container)
som_section_data (osection)->copy_data->container =
som_section_data (osection)->copy_data->container->output_section;
return TRUE;
}
static bfd_boolean
som_bfd_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
{
if (ibfd->xvec->flavour != bfd_target_som_flavour
|| obfd->xvec->flavour != bfd_target_som_flavour)
return TRUE;
obj_som_exec_data (obfd) = bfd_zalloc (obfd, (bfd_size_type) sizeof (struct som_exec_data));
if (obj_som_exec_data (obfd) == NULL)
return FALSE;
memcpy (obj_som_exec_data (obfd), obj_som_exec_data (ibfd),
sizeof (struct som_exec_data));
return TRUE;
}
static bfd_boolean
som_bfd_print_private_bfd_data (bfd *abfd, void *farg)
{
struct som_exec_auxhdr *exec_header;
struct aux_id* auxhdr;
FILE *f;
f = (FILE *) farg;
exec_header = obj_som_exec_hdr (abfd);
if (exec_header)
{
fprintf (f, _("\nExec Auxiliary Header\n"));
fprintf (f, " flags ");
auxhdr = &exec_header->som_auxhdr;
if (auxhdr->mandatory)
fprintf (f, "mandatory ");
if (auxhdr->copy)
fprintf (f, "copy ");
if (auxhdr->append)
fprintf (f, "append ");
if (auxhdr->ignore)
fprintf (f, "ignore ");
fprintf (f, "\n");
fprintf (f, " type %#x\n", auxhdr->type);
fprintf (f, " length %#x\n", auxhdr->length);
fprintf (f, " text size %#lx\n", (long) exec_header->exec_tsize);
fprintf (f, " text memory offset %#lx\n", (long) exec_header->exec_tmem);
fprintf (f, " text file offset %#lx\n", (long) exec_header->exec_tfile);
fprintf (f, " data size %#lx\n", (long) exec_header->exec_dsize);
fprintf (f, " data memory offset %#lx\n", (long) exec_header->exec_dmem);
fprintf (f, " data file offset %#lx\n", (long) exec_header->exec_dfile);
fprintf (f, " bss size %#lx\n", (long) exec_header->exec_bsize);
fprintf (f, " entry point %#lx\n", (long) exec_header->exec_entry);
fprintf (f, " loader flags %#lx\n", (long) exec_header->exec_flags);
fprintf (f, " bss initializer %#lx\n", (long) exec_header->exec_bfill);
}
return TRUE;
}
bfd_boolean
bfd_som_set_section_attributes (asection *section,
int defined,
int private,
unsigned int sort_key,
int spnum)
{
if (som_section_data (section)->copy_data == NULL)
{
bfd_size_type amt = sizeof (struct som_copyable_section_data_struct);
som_section_data (section)->copy_data = bfd_zalloc (section->owner, amt);
if (som_section_data (section)->copy_data == NULL)
return FALSE;
}
som_section_data (section)->copy_data->sort_key = sort_key;
som_section_data (section)->copy_data->is_defined = defined;
som_section_data (section)->copy_data->is_private = private;
som_section_data (section)->copy_data->container = section;
som_section_data (section)->copy_data->space_number = spnum;
return TRUE;
}
bfd_boolean
bfd_som_set_subsection_attributes (asection *section,
asection *container,
int access,
unsigned int sort_key,
int quadrant,
int comdat,
int common,
int dup_common)
{
if (som_section_data (section)->copy_data == NULL)
{
bfd_size_type amt = sizeof (struct som_copyable_section_data_struct);
som_section_data (section)->copy_data = bfd_zalloc (section->owner, amt);
if (som_section_data (section)->copy_data == NULL)
return FALSE;
}
som_section_data (section)->copy_data->sort_key = sort_key;
som_section_data (section)->copy_data->access_control_bits = access;
som_section_data (section)->copy_data->quadrant = quadrant;
som_section_data (section)->copy_data->container = container;
som_section_data (section)->copy_data->is_comdat = comdat;
som_section_data (section)->copy_data->is_common = common;
som_section_data (section)->copy_data->dup_common = dup_common;
return TRUE;
}
void
bfd_som_set_symbol_type (asymbol *symbol, unsigned int type)
{
som_symbol_data (symbol)->som_type = type;
}
bfd_boolean
bfd_som_attach_aux_hdr (bfd *abfd, int type, char *string)
{
bfd_size_type amt;
if (type == VERSION_AUX_ID)
{
size_t len = strlen (string);
int pad = 0;
if (len % 4)
pad = (4 - (len % 4));
amt = sizeof (struct aux_id) + sizeof (unsigned int) + len + pad;
obj_som_version_hdr (abfd) = bfd_zalloc (abfd, amt);
if (!obj_som_version_hdr (abfd))
return FALSE;
obj_som_version_hdr (abfd)->header_id.type = VERSION_AUX_ID;
obj_som_version_hdr (abfd)->header_id.length = len + pad;
obj_som_version_hdr (abfd)->header_id.length += sizeof (int);
obj_som_version_hdr (abfd)->string_length = len;
strncpy (obj_som_version_hdr (abfd)->user_string, string, len);
}
else if (type == COPYRIGHT_AUX_ID)
{
int len = strlen (string);
int pad = 0;
if (len % 4)
pad = (4 - (len % 4));
amt = sizeof (struct aux_id) + sizeof (unsigned int) + len + pad;
obj_som_copyright_hdr (abfd) = bfd_zalloc (abfd, amt);
if (!obj_som_copyright_hdr (abfd))
return FALSE;
obj_som_copyright_hdr (abfd)->header_id.type = COPYRIGHT_AUX_ID;
obj_som_copyright_hdr (abfd)->header_id.length = len + pad;
obj_som_copyright_hdr (abfd)->header_id.length += sizeof (int);
obj_som_copyright_hdr (abfd)->string_length = len;
strcpy (obj_som_copyright_hdr (abfd)->copyright, string);
}
return TRUE;
}
bfd_boolean
bfd_som_attach_compilation_unit (bfd *abfd,
const char *name,
const char *language_name,
const char *product_id,
const char *version_id)
{
COMPUNIT *n = (COMPUNIT *) bfd_zalloc (abfd, (bfd_size_type) COMPUNITSZ);
if (n == NULL)
return FALSE;
#define STRDUP(f) \
if (f != NULL) \
{ \
n->f.n_name = bfd_alloc (abfd, (bfd_size_type) strlen (f) + 1); \
if (n->f.n_name == NULL) \
return FALSE; \
strcpy (n->f.n_name, f); \
}
STRDUP (name);
STRDUP (language_name);
STRDUP (product_id);
STRDUP (version_id);
#undef STRDUP
obj_som_compilation_unit (abfd) = n;
return TRUE;
}
static bfd_boolean
som_get_section_contents (bfd *abfd,
sec_ptr section,
void *location,
file_ptr offset,
bfd_size_type count)
{
if (count == 0 || ((section->flags & SEC_HAS_CONTENTS) == 0))
return TRUE;
if ((bfd_size_type) (offset+count) > section->size
|| bfd_seek (abfd, (file_ptr) (section->filepos + offset), SEEK_SET) != 0
|| bfd_bread (location, count, abfd) != count)
return FALSE;
return TRUE;
}
static bfd_boolean
som_set_section_contents (bfd *abfd,
sec_ptr section,
const void *location,
file_ptr offset,
bfd_size_type count)
{
if (! abfd->output_has_begun)
{
som_prep_headers (abfd);
abfd->output_has_begun = TRUE;
som_begin_writing (abfd);
}
if (!som_is_subspace (section)
|| ((section->flags & SEC_HAS_CONTENTS) == 0))
return TRUE;
offset += som_section_data (section)->subspace_dict->file_loc_init_value;
if (bfd_seek (abfd, offset, SEEK_SET) != 0)
return FALSE;
if (bfd_bwrite (location, count, abfd) != count)
return FALSE;
return TRUE;
}
static bfd_boolean
som_set_arch_mach (bfd *abfd,
enum bfd_architecture arch,
unsigned long machine)
{
return bfd_default_set_arch_mach (abfd, arch, machine);
}
static bfd_boolean
som_find_nearest_line (bfd *abfd ATTRIBUTE_UNUSED,
asection *section ATTRIBUTE_UNUSED,
asymbol **symbols ATTRIBUTE_UNUSED,
bfd_vma offset ATTRIBUTE_UNUSED,
const char **filename_ptr ATTRIBUTE_UNUSED,
const char **functionname_ptr ATTRIBUTE_UNUSED,
unsigned int *line_ptr ATTRIBUTE_UNUSED)
{
return FALSE;
}
static int
som_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED,
bfd_boolean reloc ATTRIBUTE_UNUSED)
{
(*_bfd_error_handler) (_("som_sizeof_headers unimplemented"));
fflush (stderr);
abort ();
return 0;
}
static char
som_section_type (const char *s)
{
const struct section_to_type *t;
for (t = &stt[0]; t->section; t++)
if (!strcmp (s, t->section))
return t->type;
return '?';
}
static int
som_decode_symclass (asymbol *symbol)
{
char c;
if (bfd_is_com_section (symbol->section))
return 'C';
if (bfd_is_und_section (symbol->section))
return 'U';
if (bfd_is_ind_section (symbol->section))
return 'I';
if (symbol->flags & BSF_WEAK)
return 'W';
if (!(symbol->flags & (BSF_GLOBAL | BSF_LOCAL)))
return '?';
if (bfd_is_abs_section (symbol->section)
|| (som_symbol_data (symbol) != NULL
&& som_symbol_data (symbol)->som_type == SYMBOL_TYPE_ABSOLUTE))
c = 'a';
else if (symbol->section)
c = som_section_type (symbol->section->name);
else
return '?';
if (symbol->flags & BSF_GLOBAL)
c = TOUPPER (c);
return c;
}
static void
som_get_symbol_info (bfd *ignore_abfd ATTRIBUTE_UNUSED,
asymbol *symbol,
symbol_info *ret)
{
ret->type = som_decode_symclass (symbol);
if (ret->type != 'U')
ret->value = symbol->value + symbol->section->vma;
else
ret->value = 0;
ret->name = symbol->name;
}
static bfd_boolean
som_bfd_count_ar_symbols (bfd *abfd,
struct lst_header *lst_header,
symindex *count)
{
unsigned int i;
unsigned int *hash_table = NULL;
bfd_size_type amt;
file_ptr lst_filepos = bfd_tell (abfd) - sizeof (struct lst_header);
amt = lst_header->hash_size;
amt *= sizeof (unsigned int);
hash_table = bfd_malloc (amt);
if (hash_table == NULL && lst_header->hash_size != 0)
goto error_return;
*count = 0;
if (bfd_bread ((void *) hash_table, amt, abfd) != amt)
goto error_return;
for (i = 0; i < lst_header->hash_size; i++)
{
struct lst_symbol_record lst_symbol;
if (hash_table[i] == 0)
continue;
if (bfd_seek (abfd, lst_filepos + hash_table[i], SEEK_SET) != 0)
goto error_return;
amt = sizeof (lst_symbol);
if (bfd_bread ((void *) &lst_symbol, amt, abfd) != amt)
goto error_return;
(*count)++;
while (lst_symbol.next_entry)
{
if (bfd_seek (abfd, lst_filepos + lst_symbol.next_entry, SEEK_SET)
!= 0)
goto error_return;
amt = sizeof (lst_symbol);
if (bfd_bread ((void *) &lst_symbol, amt, abfd) != amt)
goto error_return;
(*count)++;
}
}
if (hash_table != NULL)
free (hash_table);
return TRUE;
error_return:
if (hash_table != NULL)
free (hash_table);
return FALSE;
}
static bfd_boolean
som_bfd_fill_in_ar_symbols (bfd *abfd,
struct lst_header *lst_header,
carsym **syms)
{
unsigned int i, len;
carsym *set = syms[0];
unsigned int *hash_table = NULL;
struct som_entry *som_dict = NULL;
bfd_size_type amt;
file_ptr lst_filepos = bfd_tell (abfd) - sizeof (struct lst_header);
amt = lst_header->hash_size;
amt *= sizeof (unsigned int);
hash_table = bfd_malloc (amt);
if (hash_table == NULL && lst_header->hash_size != 0)
goto error_return;
if (bfd_bread ((void *) hash_table, amt, abfd) != amt)
goto error_return;
if (bfd_seek (abfd, lst_filepos + lst_header->dir_loc, SEEK_SET) != 0)
goto error_return;
amt = lst_header->module_count;
amt *= sizeof (struct som_entry);
som_dict = bfd_malloc (amt);
if (som_dict == NULL && lst_header->module_count != 0)
goto error_return;
if (bfd_bread ((void *) som_dict, amt, abfd) != amt)
goto error_return;
for (i = 0; i < lst_header->hash_size; i++)
{
struct lst_symbol_record lst_symbol;
if (hash_table[i] == 0)
continue;
if (bfd_seek (abfd, lst_filepos + hash_table[i], SEEK_SET) != 0)
goto error_return;
amt = sizeof (lst_symbol);
if (bfd_bread ((void *) &lst_symbol, amt, abfd) != amt)
goto error_return;
if (bfd_seek (abfd, lst_filepos + lst_header->string_loc
+ lst_symbol.name.n_strx - 4, SEEK_SET) != 0)
goto error_return;
if (bfd_bread (&len, (bfd_size_type) 4, abfd) != 4)
goto error_return;
set->name = bfd_zalloc (abfd, (bfd_size_type) len + 1);
if (!set->name)
goto error_return;
if (bfd_bread (set->name, (bfd_size_type) len, abfd) != len)
goto error_return;
set->name[len] = 0;
set->file_offset = som_dict[lst_symbol.som_index].location
- sizeof (struct ar_hdr);
set++;
while (lst_symbol.next_entry)
{
if (bfd_seek (abfd, lst_filepos + lst_symbol.next_entry, SEEK_SET)
!= 0)
goto error_return;
amt = sizeof (lst_symbol);
if (bfd_bread ((void *) &lst_symbol, amt, abfd) != amt)
goto error_return;
if (bfd_seek (abfd, lst_filepos + lst_header->string_loc
+ lst_symbol.name.n_strx - 4, SEEK_SET) != 0)
goto error_return;
if (bfd_bread (&len, (bfd_size_type) 4, abfd) != 4)
goto error_return;
set->name = bfd_zalloc (abfd, (bfd_size_type) len + 1);
if (!set->name)
goto error_return;
if (bfd_bread (set->name, (bfd_size_type) len, abfd) != len)
goto error_return;
set->name[len] = 0;
set->file_offset = som_dict[lst_symbol.som_index].location
- sizeof (struct ar_hdr);
set++;
}
}
if (hash_table != NULL)
free (hash_table);
if (som_dict != NULL)
free (som_dict);
return TRUE;
error_return:
if (hash_table != NULL)
free (hash_table);
if (som_dict != NULL)
free (som_dict);
return FALSE;
}
static bfd_boolean
som_slurp_armap (bfd *abfd)
{
struct lst_header lst_header;
struct ar_hdr ar_header;
unsigned int parsed_size;
struct artdata *ardata = bfd_ardata (abfd);
char nextname[17];
bfd_size_type amt = 16;
int i = bfd_bread ((void *) nextname, amt, abfd);
if (i == 0)
return TRUE;
if (i != 16)
return FALSE;
if (bfd_seek (abfd, (file_ptr) -16, SEEK_CUR) != 0)
return FALSE;
if (strncmp (nextname, "/ ", 16))
{
bfd_has_map (abfd) = FALSE;
return TRUE;
}
amt = sizeof (struct ar_hdr);
if (bfd_bread ((void *) &ar_header, amt, abfd) != amt)
return FALSE;
if (strncmp (ar_header.ar_fmag, ARFMAG, 2))
{
bfd_set_error (bfd_error_malformed_archive);
return FALSE;
}
errno = 0;
parsed_size = strtol (ar_header.ar_size, NULL, 10);
if (errno != 0)
{
bfd_set_error (bfd_error_malformed_archive);
return FALSE;
}
ardata->first_file_filepos = bfd_tell (abfd) + parsed_size;
amt = sizeof (struct lst_header);
if (bfd_bread ((void *) &lst_header, amt, abfd) != amt)
return FALSE;
if (lst_header.a_magic != LIBMAGIC)
{
bfd_set_error (bfd_error_malformed_archive);
return FALSE;
}
if (! som_bfd_count_ar_symbols (abfd, &lst_header, &ardata->symdef_count))
return FALSE;
if (bfd_seek (abfd, (ardata->first_file_filepos - parsed_size
+ sizeof (struct lst_header)), SEEK_SET) != 0)
return FALSE;
ardata->cache = 0;
amt = ardata->symdef_count;
amt *= sizeof (carsym);
ardata->symdefs = bfd_alloc (abfd, amt);
if (!ardata->symdefs)
return FALSE;
if (! som_bfd_fill_in_ar_symbols (abfd, &lst_header, &ardata->symdefs))
return FALSE;
if (bfd_seek (abfd, ardata->first_file_filepos, SEEK_SET) != 0)
return FALSE;
bfd_has_map (abfd) = TRUE;
return TRUE;
}
static bfd_boolean
som_bfd_prep_for_ar_write (bfd *abfd,
unsigned int *num_syms,
unsigned int *stringsize)
{
bfd *curr_bfd = abfd->archive_head;
*num_syms = 0;
*stringsize = 0;
while (curr_bfd != NULL)
{
unsigned int curr_count, i;
som_symbol_type *sym;
if (curr_bfd->format != bfd_object
|| curr_bfd->xvec->flavour != bfd_target_som_flavour)
{
curr_bfd = curr_bfd->next;
continue;
}
if (! som_slurp_symbol_table (curr_bfd))
return FALSE;
sym = obj_som_symtab (curr_bfd);
curr_count = bfd_get_symcount (curr_bfd);
for (i = 0; i < curr_count; i++, sym++)
{
struct som_misc_symbol_info info;
som_bfd_derive_misc_symbol_info (curr_bfd, &sym->symbol, &info);
if (info.symbol_type == ST_NULL
|| info.symbol_type == ST_SYM_EXT
|| info.symbol_type == ST_ARG_EXT)
continue;
if (info.symbol_scope != SS_UNIVERSAL
&& info.symbol_type != ST_STORAGE)
continue;
if (bfd_is_und_section (sym->symbol.section))
continue;
(*num_syms)++;
*stringsize = *stringsize + strlen (sym->symbol.name) + 5;
while (*stringsize % 4)
(*stringsize)++;
}
curr_bfd = curr_bfd->next;
}
return TRUE;
}
static unsigned int
som_bfd_ar_symbol_hash (asymbol *symbol)
{
unsigned int len = strlen (symbol->name);
if (len == 1)
return 0x1000100 | (symbol->name[0] << 16) | symbol->name[0];
return ((len & 0x7f) << 24) | (symbol->name[1] << 16)
| (symbol->name[len - 2] << 8) | symbol->name[len - 1];
}
static bfd_boolean
som_bfd_ar_write_symbol_stuff (bfd *abfd,
unsigned int nsyms,
unsigned int string_size,
struct lst_header lst,
unsigned elength)
{
file_ptr lst_filepos;
char *strings = NULL, *p;
struct lst_symbol_record *lst_syms = NULL, *curr_lst_sym;
bfd *curr_bfd;
unsigned int *hash_table = NULL;
struct som_entry *som_dict = NULL;
struct lst_symbol_record **last_hash_entry = NULL;
unsigned int curr_som_offset, som_index = 0;
bfd_size_type amt;
amt = lst.hash_size;
amt *= sizeof (unsigned int);
hash_table = bfd_zmalloc (amt);
if (hash_table == NULL && lst.hash_size != 0)
goto error_return;
amt = lst.module_count;
amt *= sizeof (struct som_entry);
som_dict = bfd_zmalloc (amt);
if (som_dict == NULL && lst.module_count != 0)
goto error_return;
amt = lst.hash_size;
amt *= sizeof (struct lst_symbol_record *);
last_hash_entry = bfd_zmalloc (amt);
if (last_hash_entry == NULL && lst.hash_size != 0)
goto error_return;
lst_filepos = bfd_tell (abfd) - sizeof (struct lst_header);
som_index = 0;
curr_som_offset = 8 + 2 * sizeof (struct ar_hdr) + lst.file_end;
if (elength)
curr_som_offset += elength;
curr_som_offset = (curr_som_offset + 0x1) & ~0x1;
amt = nsyms;
amt *= sizeof (struct lst_symbol_record);
lst_syms = bfd_malloc (amt);
if (lst_syms == NULL && nsyms != 0)
goto error_return;
strings = bfd_malloc ((bfd_size_type) string_size);
if (strings == NULL && string_size != 0)
goto error_return;
p = strings;
curr_lst_sym = lst_syms;
curr_bfd = abfd->archive_head;
while (curr_bfd != NULL)
{
unsigned int curr_count, i;
som_symbol_type *sym;
if (curr_bfd->format != bfd_object
|| curr_bfd->xvec->flavour != bfd_target_som_flavour)
{
curr_bfd = curr_bfd->next;
continue;
}
if (! som_slurp_symbol_table (curr_bfd))
goto error_return;
sym = obj_som_symtab (curr_bfd);
curr_count = bfd_get_symcount (curr_bfd);
for (i = 0; i < curr_count; i++, sym++)
{
struct som_misc_symbol_info info;
som_bfd_derive_misc_symbol_info (curr_bfd, &sym->symbol, &info);
if (info.symbol_type == ST_NULL
|| info.symbol_type == ST_SYM_EXT
|| info.symbol_type == ST_ARG_EXT)
continue;
if (info.symbol_scope != SS_UNIVERSAL
&& info.symbol_type != ST_STORAGE)
continue;
if (bfd_is_und_section (sym->symbol.section))
continue;
if (som_dict[som_index].location == 0)
{
som_dict[som_index].location = curr_som_offset;
som_dict[som_index].length = arelt_size (curr_bfd);
}
curr_lst_sym->hidden = 0;
curr_lst_sym->secondary_def = info.secondary_def;
curr_lst_sym->symbol_type = info.symbol_type;
curr_lst_sym->symbol_scope = info.symbol_scope;
curr_lst_sym->check_level = 0;
curr_lst_sym->must_qualify = 0;
curr_lst_sym->initially_frozen = 0;
curr_lst_sym->memory_resident = 0;
curr_lst_sym->is_common = bfd_is_com_section (sym->symbol.section);
curr_lst_sym->dup_common = info.dup_common;
curr_lst_sym->xleast = 3;
curr_lst_sym->arg_reloc = info.arg_reloc;
curr_lst_sym->name.n_strx = p - strings + 4;
curr_lst_sym->qualifier_name.n_strx = 0;
curr_lst_sym->symbol_info = info.symbol_info;
curr_lst_sym->symbol_value = info.symbol_value | info.priv_level;
curr_lst_sym->symbol_descriptor = 0;
curr_lst_sym->reserved = 0;
curr_lst_sym->som_index = som_index;
curr_lst_sym->symbol_key = som_bfd_ar_symbol_hash (&sym->symbol);
curr_lst_sym->next_entry = 0;
if (hash_table[curr_lst_sym->symbol_key % lst.hash_size])
{
struct lst_symbol_record *tmp;
tmp = last_hash_entry[curr_lst_sym->symbol_key % lst.hash_size];
tmp->next_entry
= (curr_lst_sym - lst_syms) * sizeof (struct lst_symbol_record)
+ lst.hash_size * 4
+ lst.module_count * sizeof (struct som_entry)
+ sizeof (struct lst_header);
}
else
hash_table[curr_lst_sym->symbol_key % lst.hash_size]
= (curr_lst_sym - lst_syms) * sizeof (struct lst_symbol_record)
+ lst.hash_size * 4
+ lst.module_count * sizeof (struct som_entry)
+ sizeof (struct lst_header);
last_hash_entry[curr_lst_sym->symbol_key % lst.hash_size]
= curr_lst_sym;
bfd_put_32 (abfd, strlen (sym->symbol.name), p);
p += 4;
strcpy (p, sym->symbol.name);
p += strlen (sym->symbol.name) + 1;
while ((int) p % 4)
{
bfd_put_8 (abfd, 0, p);
p++;
}
curr_lst_sym++;
}
curr_som_offset += arelt_size (curr_bfd) + sizeof (struct ar_hdr);
curr_som_offset = (curr_som_offset + 0x1) &~ (unsigned) 1;
curr_bfd = curr_bfd->next;
som_index++;
}
amt = lst.hash_size * 4;
if (bfd_bwrite ((void *) hash_table, amt, abfd) != amt)
goto error_return;
amt = lst.module_count * sizeof (struct som_entry);
if (bfd_bwrite ((void *) som_dict, amt, abfd) != amt)
goto error_return;
amt = nsyms * sizeof (struct lst_symbol_record);
if (bfd_bwrite ((void *) lst_syms, amt, abfd) != amt)
goto error_return;
amt = string_size;
if (bfd_bwrite ((void *) strings, amt, abfd) != amt)
goto error_return;
if (hash_table != NULL)
free (hash_table);
if (som_dict != NULL)
free (som_dict);
if (last_hash_entry != NULL)
free (last_hash_entry);
if (lst_syms != NULL)
free (lst_syms);
if (strings != NULL)
free (strings);
return TRUE;
error_return:
if (hash_table != NULL)
free (hash_table);
if (som_dict != NULL)
free (som_dict);
if (last_hash_entry != NULL)
free (last_hash_entry);
if (lst_syms != NULL)
free (lst_syms);
if (strings != NULL)
free (strings);
return FALSE;
}
static bfd_boolean
som_write_armap (bfd *abfd,
unsigned int elength,
struct orl *map ATTRIBUTE_UNUSED,
unsigned int orl_count ATTRIBUTE_UNUSED,
int stridx ATTRIBUTE_UNUSED)
{
bfd *curr_bfd;
struct stat statbuf;
unsigned int i, lst_size, nsyms, stringsize;
struct ar_hdr hdr;
struct lst_header lst;
int *p;
bfd_size_type amt;
if (stat (abfd->filename, &statbuf) != 0)
{
bfd_set_error (bfd_error_system_call);
return FALSE;
}
bfd_ardata (abfd)->armap_timestamp = statbuf.st_mtime + 60;
lst_size = sizeof (struct lst_header);
lst.system_id = CPU_PA_RISC1_0;
lst.a_magic = LIBMAGIC;
lst.version_id = VERSION_ID;
lst.file_time.secs = 0;
lst.file_time.nanosecs = 0;
lst.hash_loc = lst_size;
lst.hash_size = SOM_LST_HASH_SIZE;
lst_size += 4 * SOM_LST_HASH_SIZE;
curr_bfd = abfd->archive_head;
lst.module_count = 0;
while (curr_bfd != NULL)
{
if (curr_bfd->format == bfd_object
&& curr_bfd->xvec->flavour == bfd_target_som_flavour)
lst.module_count++;
curr_bfd = curr_bfd->next;
}
lst.module_limit = lst.module_count;
lst.dir_loc = lst_size;
lst_size += sizeof (struct som_entry) * lst.module_count;
lst.export_loc = 0;
lst.export_count = 0;
lst.import_loc = 0;
lst.aux_loc = 0;
lst.aux_size = 0;
if (! som_bfd_prep_for_ar_write (abfd, &nsyms, &stringsize))
return FALSE;
lst_size += sizeof (struct lst_symbol_record) * nsyms;
lst.string_loc = lst_size;
lst.string_size = stringsize;
lst_size += stringsize;
lst.free_list = 0;
lst.file_end = lst_size;
p = (int *) &lst;
lst.checksum = 0;
for (i = 0; i < sizeof (struct lst_header) / sizeof (int) - 1; i++)
lst.checksum ^= *p++;
sprintf (hdr.ar_name, "/ ");
sprintf (hdr.ar_date, "%ld", bfd_ardata (abfd)->armap_timestamp);
sprintf (hdr.ar_uid, "%ld", (long) getuid ());
sprintf (hdr.ar_gid, "%ld", (long) getgid ());
sprintf (hdr.ar_mode, "%-8o", (unsigned int) statbuf.st_mode);
sprintf (hdr.ar_size, "%-10d", (int) lst_size);
hdr.ar_fmag[0] = '`';
hdr.ar_fmag[1] = '\012';
for (i = 0; i < sizeof (struct ar_hdr); i++)
if (((char *) (&hdr))[i] == '\0')
(((char *) (&hdr))[i]) = ' ';
amt = sizeof (struct ar_hdr);
if (bfd_bwrite ((void *) &hdr, amt, abfd) != amt)
return FALSE;
amt = sizeof (struct lst_header);
if (bfd_bwrite ((void *) &lst, amt, abfd) != amt)
return FALSE;
if (!som_bfd_ar_write_symbol_stuff (abfd, nsyms, stringsize, lst, elength))
return FALSE;
return TRUE;
}
static bfd_boolean
som_bfd_free_cached_info (bfd *abfd)
{
asection *o;
if (bfd_get_format (abfd) != bfd_object)
return TRUE;
#define FREE(x) if (x != NULL) { free (x); x = NULL; }
FREE (obj_som_symtab (abfd));
FREE (obj_som_stringtab (abfd));
for (o = abfd->sections; o != NULL; o = o->next)
{
o->reloc_count = (unsigned) -1;
FREE (som_section_data (o)->reloc_stream);
FREE (o->relocation);
}
#undef FREE
return TRUE;
}
#define som_get_section_contents_in_window_with_mode \
_bfd_generic_get_section_contents_in_window_with_mode
static bfd_boolean
som_bfd_link_split_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
{
return som_is_subspace (sec) && sec->size > 240000;
}
#define som_close_and_cleanup som_bfd_free_cached_info
#define som_read_ar_hdr _bfd_generic_read_ar_hdr
#define som_openr_next_archived_file bfd_generic_openr_next_archived_file
#define som_get_elt_at_index _bfd_generic_get_elt_at_index
#define som_generic_stat_arch_elt bfd_generic_stat_arch_elt
#define som_truncate_arname bfd_bsd_truncate_arname
#define som_slurp_extended_name_table _bfd_slurp_extended_name_table
#define som_construct_extended_name_table _bfd_archive_coff_construct_extended_name_table
#define som_update_armap_timestamp bfd_true
#define som_bfd_is_target_special_symbol ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false)
#define som_get_lineno _bfd_nosymbols_get_lineno
#define som_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol
#define som_read_minisymbols _bfd_generic_read_minisymbols
#define som_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol
#define som_get_section_contents_in_window _bfd_generic_get_section_contents_in_window
#define som_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents
#define som_bfd_relax_section bfd_generic_relax_section
#define som_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
#define som_bfd_link_hash_table_free _bfd_generic_link_hash_table_free
#define som_bfd_link_add_symbols _bfd_generic_link_add_symbols
#define som_bfd_link_just_syms _bfd_generic_link_just_syms
#define som_bfd_final_link _bfd_generic_final_link
#define som_bfd_gc_sections bfd_generic_gc_sections
#define som_bfd_merge_sections bfd_generic_merge_sections
#define som_bfd_is_group_section bfd_generic_is_group_section
#define som_bfd_discard_group bfd_generic_discard_group
#define som_section_already_linked _bfd_generic_section_already_linked
#define som_bfd_merge_private_bfd_data _bfd_generic_bfd_merge_private_bfd_data
#define som_bfd_copy_private_header_data _bfd_generic_bfd_copy_private_header_data
#define som_bfd_set_private_flags _bfd_generic_bfd_set_private_flags
#define som_find_inliner_info _bfd_nosymbols_find_inliner_info
const bfd_target som_vec =
{
"som",
bfd_target_som_flavour,
BFD_ENDIAN_BIG,
BFD_ENDIAN_BIG,
(HAS_RELOC | EXEC_P |
HAS_LINENO | HAS_DEBUG |
HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED | DYNAMIC),
(SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS | SEC_LINK_ONCE
| SEC_ALLOC | SEC_LOAD | SEC_RELOC),
0,
'/',
14,
bfd_getb64, bfd_getb_signed_64, bfd_putb64,
bfd_getb32, bfd_getb_signed_32, bfd_putb32,
bfd_getb16, bfd_getb_signed_16, bfd_putb16,
bfd_getb64, bfd_getb_signed_64, bfd_putb64,
bfd_getb32, bfd_getb_signed_32, bfd_putb32,
bfd_getb16, bfd_getb_signed_16, bfd_putb16,
{_bfd_dummy_target,
som_object_p,
bfd_generic_archive_p,
_bfd_dummy_target
},
{
bfd_false,
som_mkobject,
_bfd_generic_mkarchive,
bfd_false
},
{
bfd_false,
som_write_object_contents,
_bfd_write_archive_contents,
bfd_false,
},
#undef som
BFD_JUMP_TABLE_GENERIC (som),
BFD_JUMP_TABLE_COPY (som),
BFD_JUMP_TABLE_CORE (_bfd_nocore),
BFD_JUMP_TABLE_ARCHIVE (som),
BFD_JUMP_TABLE_SYMBOLS (som),
BFD_JUMP_TABLE_RELOCS (som),
BFD_JUMP_TABLE_WRITE (som),
BFD_JUMP_TABLE_LINK (som),
BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
NULL,
NULL
};
#endif