/* tc-hppa.c -- Assemble for the PA
Copyright 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
- 2002 Free Software Foundation, Inc.
+ 2002, 2003 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
#ifdef OBJ_ELF
#include "dwarf2dbg.h"
-/* A "convient" place to put object file dependencies which do
+/* A "convenient" place to put object file dependencies which do
not need to be seen outside of tc-hppa.c. */
/* Object file formats specify relocation types. */
/* Nonzero if this subspace contains only code. */
char code_only;
+ /* Nonzero if this is a comdat subspace. */
+ char comdat;
+
/* Nonzero if this is a common subspace. */
char common;
static void pa_check_current_space_and_subspace PARAMS ((void));
#endif
-#if !(defined (OBJ_ELF) && defined (TE_LINUX))
+#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
static void pa_text PARAMS ((int));
static void pa_data PARAMS ((int));
static void pa_comm PARAMS ((int));
asection *, int));
static ssd_chain_struct *create_new_subspace PARAMS ((sd_chain_struct *,
char *, int, int,
- int, int, int,
+ int, int, int, int,
int, int, int, int,
int, asection *));
static ssd_chain_struct *update_subspace PARAMS ((sd_chain_struct *,
char *, int, int, int,
int, int, int, int,
- int, int, int,
+ int, int, int, int,
asection *));
static sd_chain_struct *is_defined_space PARAMS ((char *));
static ssd_chain_struct *is_defined_subspace PARAMS ((char *));
static void pa_vtable_inherit PARAMS ((int));
#endif
-/* File and gloally scoped variable declarations. */
+/* File and globally scoped variable declarations. */
#ifdef OBJ_SOM
/* Root and final entry in the space chain. */
/* handle of the OPCODE hash table */
static struct hash_control *op_hash = NULL;
+/* These characters can be suffixes of opcode names and they may be
+ followed by meaningful whitespace. We don't include `,' and `!'
+ as they never appear followed by meaningful whitespace. */
+const char hppa_symbol_chars[] = "*?=<>";
+
/* Table of pseudo ops for the PA. FIXME -- how many of these
are now redundant with the overall GAS and the object file
dependent tables? */
{"byte", pa_cons, 1},
{"call", pa_call, 0},
{"callinfo", pa_callinfo, 0},
-#if defined (OBJ_ELF) && defined (TE_LINUX)
+#if defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD))
{"code", obj_elf_text, 0},
#else
{"code", pa_text, 0},
{"compiler", pa_compiler, 0},
#endif
{"copyright", pa_copyright, 0},
-#if !(defined (OBJ_ELF) && defined (TE_LINUX))
+#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
{"data", pa_data, 0},
#endif
{"double", pa_float_cons, 'd'},
{"dword", pa_cons, 8},
{"end", pa_end, 0},
{"end_brtab", pa_brtab, 0},
-#if !(defined (OBJ_ELF) && defined (TE_LINUX))
+#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
{"end_try", pa_try, 0},
#endif
{"enter", pa_enter, 0},
{"equ", pa_equ, 0},
{"exit", pa_exit, 0},
{"export", pa_export, 0},
-#ifdef OBJ_ELF
- {"file", dwarf2_directive_file, 0 },
-#endif
{"fill", pa_fill, 0},
{"float", pa_float_cons, 'f'},
{"half", pa_cons, 2},
{"lcomm", pa_lcomm, 0},
{"leave", pa_leave, 0},
{"level", pa_level, 0},
-#ifdef OBJ_ELF
- {"loc", dwarf2_directive_loc, 0 },
-#endif
{"long", pa_cons, 4},
{"lsym", pa_lsym, 0},
#ifdef OBJ_SOM
#ifdef OBJ_SOM
{"subspa", pa_subspace, 0},
#endif
-#if !(defined (OBJ_ELF) && defined (TE_LINUX))
+#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
{"text", pa_text, 0},
#endif
{"version", pa_version, 0},
static struct pa_it the_insn;
-/* Points to the end of an expression just parsed by get_expressoin
+/* Points to the end of an expression just parsed by get_expression
and friends. FIXME. This shouldn't be handled with a file-global
variable. */
static char *expr_end;
{"%dp", 27},
{"%eiem", 15},
{"%eirr", 23},
+ {"%farg0", 5},
+ {"%farg1", 6},
+ {"%farg2", 7},
+ {"%farg3", 8},
{"%fr0", 0 + FP_REG_BASE},
{"%fr0l", 0 + FP_REG_BASE},
{"%fr0r", 0 + FP_REG_BASE + FP_REG_RSEL},
{"%fr9", 9 + FP_REG_BASE},
{"%fr9l", 9 + FP_REG_BASE},
{"%fr9r", 9 + FP_REG_BASE + FP_REG_RSEL},
+ {"%fret", 4},
{"%hta", 25},
{"%iir", 19},
{"%ior", 21},
{"%sr5", 5},
{"%sr6", 6},
{"%sr7", 7},
+ {"%t1", 22},
+ {"%t2", 21},
+ {"%t3", 20},
+ {"%t4", 19},
+ {"%tf1", 11},
+ {"%tf2", 10},
+ {"%tf3", 9},
+ {"%tf4", 8},
{"%tr0", 24},
{"%tr1", 25},
{"%tr2", 26},
static struct default_subspace_dict pa_def_subspaces[] =
{
- {"$CODE$", 1, 1, 1, 0, 0, 0, 24, 0x2c, 0, 8, 0, 0, SUBSEG_CODE},
- {"$DATA$", 1, 1, 0, 0, 0, 0, 24, 0x1f, 1, 8, 1, 1, SUBSEG_DATA},
- {"$LIT$", 1, 1, 0, 0, 0, 0, 16, 0x2c, 0, 8, 0, 0, SUBSEG_LIT},
- {"$MILLICODE$", 1, 1, 0, 0, 0, 0, 8, 0x2c, 0, 8, 0, 0, SUBSEG_MILLI},
- {"$BSS$", 1, 1, 0, 0, 0, 1, 80, 0x1f, 1, 8, 1, 1, SUBSEG_BSS},
- {NULL, 0, 1, 0, 0, 0, 0, 255, 0x1f, 0, 4, 0, 0, 0}
+ {"$CODE$", 1, 1, 1, 0, 0, 0, 0, 24, 0x2c, 0, 8, 0, 0, SUBSEG_CODE},
+ {"$DATA$", 1, 1, 0, 0, 0, 0, 0, 24, 0x1f, 1, 8, 1, 1, SUBSEG_DATA},
+ {"$LIT$", 1, 1, 0, 0, 0, 0, 0, 16, 0x2c, 0, 8, 0, 0, SUBSEG_LIT},
+ {"$MILLICODE$", 1, 1, 0, 0, 0, 0, 0, 8, 0x2c, 0, 8, 0, 0, SUBSEG_MILLI},
+ {"$BSS$", 1, 1, 0, 0, 0, 0, 1, 80, 0x1f, 1, 8, 1, 1, SUBSEG_BSS},
+ {NULL, 0, 1, 0, 0, 0, 0, 0, 255, 0x1f, 0, 4, 0, 0, 0}
};
static struct default_space_dict pa_def_spaces[] =
continue; \
}
-/* Simple range checking for FIELD againt HIGH and LOW bounds.
+/* Simple range checking for FIELD against HIGH and LOW bounds.
IGNORE is used to suppress the error message. */
#define CHECK_FIELD(FIELD, HIGH, LOW, IGNORE) \
} \
}
-/* Simple alignment checking for FIELD againt ALIGN (a power of two).
+/* Simple alignment checking for FIELD against ALIGN (a power of two).
IGNORE is used to suppress the error message. */
#define CHECK_ALIGN(FIELD, ALIGN, IGNORE) \
{
if (1
#ifdef OBJ_SOM
- && current_space == label_chain->lss_space && label_chain->lss_label
+ && current_space == label_chain->lss_space && label_chain->lss_label
#endif
#ifdef OBJ_ELF
- && now_seg == label_chain->lss_segment && label_chain->lss_label
+ && now_seg == label_chain->lss_segment && label_chain->lss_label
#endif
)
{
/* Get a base relocation type. */
if (is_DP_relative (*exp))
rel_type = R_HPPA_GOTOFF;
+ else if (is_PC_relative (*exp))
+ rel_type = R_HPPA_PCREL_CALL;
else if (is_complex (*exp))
rel_type = R_HPPA_COMPLEX;
else
/* Assemble the instruction. Results are saved into "the_insn". */
pa_ip (str);
- /* Get somewhere to put the assembled instrution. */
+ /* Get somewhere to put the assembled instruction. */
to = frag_more (4);
/* Output the opcode. */
/* If this instruction is specific to a particular architecture,
then set a new architecture. */
/* But do not automatically promote to pa2.0. The automatic promotion
- crud is for compatability with HP's old assemblers only. */
+ crud is for compatibility with HP's old assemblers only. */
if (insn->arch < 20
&& bfd_get_mach (stdoutput) < insn->arch)
{
args++;
switch (*args)
{
- /* Handle FP compare conditions. */
- case 'f':
- cond = pa_parse_fp_cmp_cond (&s);
- INSERT_FIELD_AND_CONTINUE (opcode, cond, 0);
+ /* Handle FP compare conditions. */
+ case 'f':
+ cond = pa_parse_fp_cmp_cond (&s);
+ INSERT_FIELD_AND_CONTINUE (opcode, cond, 0);
/* Handle an add condition. */
case 'A':
case 'a':
- cmpltr = 0;
- flag = 0;
+ cmpltr = 0;
+ flag = 0;
if (*s == ',')
{
s++;
}
else if (*s == '*')
break;
- name = s;
name = s;
while (*s != ',' && *s != ' ' && *s != '\t')
flag = 1;
}
/* ",*" is a valid condition. */
- else if (*args == 'a')
+ else if (*args == 'a' || *name)
as_bad (_("Invalid Add Condition: %s"), name);
*s = c;
}
}
else if (*s == '*')
break;
- name = s;
name = s;
while (*s != ',' && *s != ' ' && *s != '\t')
flag = 1;
}
/* ",*" is a valid condition. */
- else if (*args != 'S')
+ else if (*args != 'S' || *name)
as_bad (_("Invalid Compare/Subtract Condition: %s"),
name);
*s = c;
flag = 1;
}
/* ",*" is a valid condition. */
- else if (*args != 'L')
+ else if (*args != 'L' || *name)
as_bad (_("Invalid Logical Instruction Condition."));
*s = c;
}
continue;
}
/* ",*" is a valid condition. */
- else if (*args != 'X')
+ else if (*args != 'X' || *name)
as_bad (_("Invalid Shift/Extract/Deposit Condition."));
*s = c;
}
s += 3;
}
/* ",*" is a valid condition. */
- else if (*args != 'U')
+ else if (*args != 'U' || (*s != ' ' && *s != '\t'))
as_bad (_("Invalid Unit Instruction Condition."));
}
opcode |= cmpltr << 13;
the_insn.pcrel = 1;
if (!the_insn.exp.X_add_symbol
|| !strcmp (S_GET_NAME (the_insn.exp.X_add_symbol),
- "L$0\001"))
+ FAKE_LABEL_NAME))
{
num = evaluate_absolute (&the_insn);
if (num % 4)
the_insn.pcrel = 1;
if (!the_insn.exp.X_add_symbol
|| !strcmp (S_GET_NAME (the_insn.exp.X_add_symbol),
- "L$0\001"))
+ FAKE_LABEL_NAME))
{
num = evaluate_absolute (&the_insn);
if (num % 4)
the_insn.pcrel = 1;
if (!the_insn.exp.X_add_symbol
|| !strcmp (S_GET_NAME (the_insn.exp.X_add_symbol),
- "L$0\001"))
+ FAKE_LABEL_NAME))
{
num = evaluate_absolute (&the_insn);
if (num % 4)
the_insn.pcrel = 0;
if (!the_insn.exp.X_add_symbol
|| !strcmp (S_GET_NAME (the_insn.exp.X_add_symbol),
- "L$0\001"))
+ FAKE_LABEL_NAME))
{
num = evaluate_absolute (&the_insn);
if (num % 4)
failed:
/* Check if the args matched. */
- if (match == FALSE)
+ if (!match)
{
if (&insn[1] - pa_opcodes < (int) NUMOPCODES
&& !strcmp (insn->name, insn[1].name))
case R_N0SEL:
case R_N1SEL:
/* There is no symbol or addend associated with these fixups. */
- relocs[i]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
- *relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (dummy_symbol);
+ relocs[i]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+ *relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (dummy_symbol);
relocs[i]->addend = 0;
break;
case R_ENTRY:
case R_EXIT:
/* There is no symbol associated with these fixups. */
- relocs[i]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
- *relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (dummy_symbol);
+ relocs[i]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+ *relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (dummy_symbol);
relocs[i]->addend = fixp->fx_offset;
break;
offsetT new_val;
int insn, val, fmt;
- if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
- fixP->fx_done = 1;
-
/* SOM uses R_HPPA_ENTRY and R_HPPA_EXIT relocations which can
never be "applied" (they are just markers). Likewise for
R_HPPA_BEGIN_BRTAB and R_HPPA_END_BRTAB. */
return;
#endif
+ if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
+ fixP->fx_done = 1;
+
/* There should have been an HPPA specific fixup associated
with the GAS fixup. */
hppa_fixP = (struct hppa_fix_struct *) fixP->tc_fix_data;
return;
}
- buf = fixP->fx_frag->fr_literal + fixP->fx_where;
+ buf = (unsigned char *) (fixP->fx_frag->fr_literal + fixP->fx_where);
insn = bfd_get_32 (stdoutput, buf);
fmt = bfd_hppa_insn2fmt (stdoutput, insn);
|| hppa_fixP->fx_r_field == e_rtsel
|| hppa_fixP->fx_r_field == e_ltsel)
new_val = ((fmt == 12 || fmt == 17 || fmt == 22) ? 8 : 0);
- /* This is truly disgusting. The machine independent code blindly
- adds in the value of the symbol being relocated against. Damn! */
- else if (fmt == 32
- && fixP->fx_addsy != NULL
- && S_GET_SEGMENT (fixP->fx_addsy) != bfd_com_section_ptr)
- new_val = hppa_field_adjust (* valP - S_GET_VALUE (fixP->fx_addsy),
- 0, hppa_fixP->fx_r_field);
#endif
else
new_val = hppa_field_adjust (* valP, 0, hppa_fixP->fx_r_field);
symbolS *sym;
int status;
char *p = *s;
- boolean have_prefix;
+ bfd_boolean have_prefix;
/* Skip whitespace before the number. */
while (*p == ' ' || *p == '\t')
num = S_GET_VALUE (sym);
/* Well, we don't really have one, but we do have a
register, so... */
- have_prefix = true;
+ have_prefix = TRUE;
}
else if (S_GET_SEGMENT (sym) == &bfd_abs_section)
num = S_GET_VALUE (sym);
/* There is where we'd come for an undefined symbol
or for an empty string. For an empty string we
will return zero. That's a concession made for
- compatability with the braindamaged HP assemblers. */
+ compatibility with the braindamaged HP assemblers. */
if (*name == 0)
num = 0;
else
expression (&insn->exp);
/* This is not perfect, but is a huge improvement over doing nothing.
- The PA assembly syntax is ambigious in a variety of ways. Consider
+ The PA assembly syntax is ambiguous in a variety of ways. Consider
this string "4 %r5" Is that the number 4 followed by the register
r5, or is that 4 MOD r5?
- If we get a modulo expresion When looking for an absolute, we try
+ If we get a modulo expression when looking for an absolute, we try
again cutting off the input string at the first whitespace character. */
if (insn->exp.X_op == O_modulus)
{
input_line_pointer = *strp;
s = *strp;
while (*s != ',' && *s != ' ' && *s != '\t')
- s++;
+ s++;
c = *s;
*s = 0;
}
/* Parse a non-negated compare/subtract completer returning the
- number (for encoding in instrutions) of the given completer. */
+ number (for encoding in instructions) of the given completer. */
static int
pa_parse_nonneg_cmpsub_cmpltr (s)
}
/* Parse a negated compare/subtract completer returning the
- number (for encoding in instrutions) of the given completer. */
+ number (for encoding in instructions) of the given completer. */
static int
pa_parse_neg_cmpsub_cmpltr (s)
}
/* Parse a 64 bit compare and branch completer returning the number (for
- encoding in instrutions) of the given completer.
+ encoding in instructions) of the given completer.
Nonnegated comparisons are returned as 0-7, negated comparisons are
returned as 8-15. */
}
/* Parse a 64 bit compare immediate and branch completer returning the number
- (for encoding in instrutions) of the given completer. */
+ (for encoding in instructions) of the given completer. */
static int
pa_parse_cmpib_64_cmpltr (s)
}
/* Parse a non-negated addition completer returning the number
- (for encoding in instrutions) of the given completer. */
+ (for encoding in instructions) of the given completer. */
static int
pa_parse_nonneg_add_cmpltr (s)
}
/* Parse a negated addition completer returning the number
- (for encoding in instrutions) of the given completer. */
+ (for encoding in instructions) of the given completer. */
static int
pa_parse_neg_add_cmpltr (s)
}
/* Parse a 64 bit wide mode add and branch completer returning the number (for
- encoding in instrutions) of the given completer. */
+ encoding in instructions) of the given completer. */
static int
pa_parse_addb_64_cmpltr (s)
{
#ifdef OBJ_SOM
- /* The BRTAB relocations are only availble in SOM (to denote
+ /* The BRTAB relocations are only available in SOM (to denote
the beginning and end of branch tables). */
char *where = frag_more (0);
if (! begin)
expression (&exp);
- /* The TRY relocations are only availble in SOM (to denote
+ /* The TRY relocations are only available in SOM (to denote
the beginning and end of exception handling regions). */
fix_new_hppa (frag_now, where - frag_now->fr_literal, 0,
demand_empty_rest_of_line ();
}
-#if !(defined (OBJ_ELF) && defined (TE_LINUX))
+#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
/* Switch to the text space. Like s_text, but delete our
label when finished. */
static void
if (symbol)
{
+ symbol_get_bfdsym (symbol)->flags |= BSF_OBJECT;
S_SET_VALUE (symbol, size);
S_SET_SEGMENT (symbol, bfd_und_section_ptr);
S_SET_EXTERNAL (symbol);
}
demand_empty_rest_of_line ();
}
-#endif /* !(defined (OBJ_ELF) && defined (TE_LINUX)) */
+#endif /* !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD))) */
/* Process a .END pseudo-op. */
}
/* Process a .ENTRY pseudo-op. .ENTRY marks the beginning of the
- procesure. */
+ procedure. */
static void
pa_entry (unused)
int unused ATTRIBUTE_UNUSED;
#endif
*input_line_pointer = c;
}
- /* Privelege level. */
+ /* Privilege level. */
else if ((strncasecmp (name, "priv_lev", 8)) == 0)
{
p = input_line_pointer;
}
else
{
- /* Sigh. To be compatable with the HP assembler and to help
+ /* Sigh. To be compatible with the HP assembler and to help
poorly written assembly code, we assign a type based on
the current segment. Note only BSF_FUNCTION really
matters, we do not need to set the full SYMBOL_TYPE_* info. */
demand_empty_rest_of_line ();
}
-/* Process the syntatical end of a procedure. Make sure all the
+/* Process the syntactical end of a procedure. Make sure all the
appropriate pseudo-ops were found within the procedure. */
static void
/* If create_flag is nonzero, then create the new space with
the attributes computed above. Else set the values in
an already existing space -- this can only happen for
- the first occurence of a built-in space. */
+ the first occurrence of a built-in space. */
if (create_flag)
space = create_new_space (space_name, spnum, loadable, defined,
private, sort, seg, 1);
int create_new;
{
char *name, *ss_name, c;
- char loadable, code_only, common, dup_common, zero, sort;
+ char loadable, code_only, comdat, common, dup_common, zero, sort;
int i, access, space_index, alignment, quadrant, applicable, flags;
sd_chain_struct *space;
ssd_chain_struct *ssd;
sort = 0;
access = 0x7f;
loadable = 1;
+ comdat = 0;
common = 0;
dup_common = 0;
code_only = 0;
if (strcasecmp (pa_def_subspaces[i].name, ss_name) == 0)
{
loadable = pa_def_subspaces[i].loadable;
+ comdat = pa_def_subspaces[i].comdat;
common = pa_def_subspaces[i].common;
dup_common = pa_def_subspaces[i].dup_common;
code_only = pa_def_subspaces[i].code_only;
*input_line_pointer = c;
loadable = 0;
}
+ else if ((strncasecmp (name, "comdat", 6) == 0))
+ {
+ *input_line_pointer = c;
+ comdat = 1;
+ }
else if ((strncasecmp (name, "common", 6) == 0))
{
*input_line_pointer = c;
flags |= (SEC_ALLOC | SEC_LOAD);
if (code_only)
flags |= SEC_CODE;
- if (common || dup_common)
- flags |= SEC_IS_COMMON;
+
+ /* These flags are used to implement various flavors of initialized
+ common. The SOM linker discards duplicate subspaces when they
+ have the same "key" symbol name. This support is more like
+ GNU linkonce than BFD common. Further, pc-relative relocations
+ are converted to section relative relocations in BFD common
+ sections. This complicates the handling of relocations in
+ common sections containing text and isn't currently supported
+ correctly in the SOM BFD backend. */
+ if (comdat || common || dup_common)
+ flags |= SEC_LINK_ONCE;
flags |= SEC_RELOC | SEC_HAS_CONTENTS;
if (ssd)
current_subspace = update_subspace (space, ss_name, loadable,
- code_only, common, dup_common,
- sort, zero, access, space_index,
- alignment, quadrant,
+ code_only, comdat, common,
+ dup_common, sort, zero, access,
+ space_index, alignment, quadrant,
section);
else
current_subspace = create_new_subspace (space, ss_name, loadable,
- code_only, common,
+ code_only, comdat, common,
dup_common, zero, sort,
access, space_index,
- alignment, quadrant, section);
+ alignment, quadrant, section);
demand_empty_rest_of_line ();
current_subspace->ssd_seg = section;
create_new_subspace (space, name,
pa_def_subspaces[i].loadable,
pa_def_subspaces[i].code_only,
+ pa_def_subspaces[i].comdat,
pa_def_subspaces[i].common,
pa_def_subspaces[i].dup_common,
pa_def_subspaces[i].zero,
order as defined by the SORT entries. */
static ssd_chain_struct *
-create_new_subspace (space, name, loadable, code_only, common,
+create_new_subspace (space, name, loadable, code_only, comdat, common,
dup_common, is_zero, sort, access, space_index,
alignment, quadrant, seg)
sd_chain_struct *space;
char *name;
- int loadable, code_only, common, dup_common, is_zero;
+ int loadable, code_only, comdat, common, dup_common, is_zero;
int sort;
int access;
int space_index;
}
#ifdef obj_set_subsection_attributes
- obj_set_subsection_attributes (seg, space->sd_seg, access,
- sort, quadrant);
+ obj_set_subsection_attributes (seg, space->sd_seg, access, sort,
+ quadrant, comdat, common, dup_common);
#endif
return chain_entry;
various arguments. Return the modified subspace chain entry. */
static ssd_chain_struct *
-update_subspace (space, name, loadable, code_only, common, dup_common, sort,
- zero, access, space_index, alignment, quadrant, section)
+update_subspace (space, name, loadable, code_only, comdat, common, dup_common,
+ sort, zero, access, space_index, alignment, quadrant, section)
sd_chain_struct *space;
char *name;
int loadable;
int code_only;
+ int comdat;
int common;
int dup_common;
int zero;
chain_entry = is_defined_subspace (name);
#ifdef obj_set_subsection_attributes
- obj_set_subsection_attributes (section, space->sd_seg, access,
- sort, quadrant);
+ obj_set_subsection_attributes (section, space->sd_seg, access, sort,
+ quadrant, comdat, common, dup_common);
#endif
return chain_entry;
{
/* Relocation types which use e_lrsel. */
case R_PARISC_DIR21L:
- case R_PARISC_DLTIND21L:
case R_PARISC_DLTREL21L:
case R_PARISC_DPREL21L:
- case R_PARISC_LTOFF_FPTR21L:
- case R_PARISC_LTOFF_TP21L:
- case R_PARISC_PCREL21L:
- case R_PARISC_PLABEL21L:
case R_PARISC_PLTOFF21L:
/* Relocation types which use e_rrsel. */
case R_PARISC_DIR14DR:
case R_PARISC_DIR14WR:
case R_PARISC_DIR17R:
- case R_PARISC_DLTIND14R:
- case R_PARISC_DLTIND14DR:
- case R_PARISC_DLTIND14WR:
case R_PARISC_DLTREL14R:
case R_PARISC_DLTREL14DR:
case R_PARISC_DLTREL14WR:
case R_PARISC_DPREL14R:
case R_PARISC_DPREL14DR:
case R_PARISC_DPREL14WR:
- case R_PARISC_PCREL14R:
- case R_PARISC_PCREL17R:
- case R_PARISC_PLABEL14R:
- case R_PARISC_LTOFF_FPTR14R:
- case R_PARISC_LTOFF_FPTR14DR:
- case R_PARISC_LTOFF_FPTR14WR:
- case R_PARISC_LTOFF_TP14R:
- case R_PARISC_LTOFF_TP14DR:
- case R_PARISC_LTOFF_TP14WR:
+ case R_PARISC_PLTOFF14R:
+ case R_PARISC_PLTOFF14DR:
+ case R_PARISC_PLTOFF14WR:
/* Other types that we reject for reduction. */
case R_PARISC_GNU_VTENTRY:
}
#endif
- if (fixp->fx_addsy && (S_IS_EXTERNAL (fixp->fx_addsy)
- || S_IS_WEAK (fixp->fx_addsy)))
- return 0;
-
/* Reject reductions of symbols in sym1-sym2 expressions when
the fixup will occur in a CODE subspace.
if (fixp->fx_addsy
&& fixp->fx_subsy
&& (hppa_fix->segment->flags & SEC_CODE))
- {
- /* Apparently sy_used_in_reloc never gets set for sub symbols. */
- symbol_mark_used_in_reloc (fixp->fx_subsy);
- return 0;
- }
+ return 0;
/* We can't adjust any relocs that use LR% and RR% field selectors.
. RR%sect+4092 == (R%sect)+4092
. RR%sect+4096 == (R%sect)-4096
and the last address loses because rounding the addend to 8k
- mutiples takes us up to 8192 with an offset of -4096.
+ multiples takes us up to 8192 with an offset of -4096.
In cases where the LR% expression is identical to the RR% one we
will never have a problem, but is so happens that gcc rounds
/* Ensure we emit a relocation for global symbols so that dynamic
linking works. */
- if (S_IS_EXTERNAL (fixp->fx_addsy) || S_IS_WEAK (fixp->fx_addsy))
+ if (S_FORCE_RELOC (fixp->fx_addsy, 1))
return 1;
/* It is necessary to force PC-relative calls/jumps to have a relocation
/* Now check to see if we're going to need a long-branch stub. */
if (fixp->fx_r_type == (int) R_HPPA_PCREL_CALL)
{
- valueT distance;
+ long pc = md_pcrel_from (fixp);
+ valueT distance, min_stub_distance;
- distance = (fixp->fx_offset + S_GET_VALUE (fixp->fx_addsy)
- - md_pcrel_from (fixp) - 8);
- if (distance + 8388608 >= 16777216
- || (hppa_fixp->fx_r_format == 17 && distance + 262144 >= 524288)
-#ifdef OBJ_ELF
- || (hppa_fixp->fx_r_format == 12 && distance + 8192 >= 16384)
+ distance = fixp->fx_offset + S_GET_VALUE (fixp->fx_addsy) - pc - 8;
+
+ /* Distance to the closest possible stub. This will detect most
+ but not all circumstances where a stub will not work. */
+ min_stub_distance = pc + 16;
+#ifdef OBJ_SOM
+ if (last_call_info != NULL)
+ min_stub_distance -= S_GET_VALUE (last_call_info->start_symbol);
#endif
+
+ if ((distance + 8388608 >= 16777216
+ && min_stub_distance <= 8388608)
+ || (hppa_fixp->fx_r_format == 17
+ && distance + 262144 >= 524288
+ && min_stub_distance <= 262144)
+ || (hppa_fixp->fx_r_format == 12
+ && distance + 8192 >= 16384
+ && min_stub_distance <= 8192)
)
return 1;
}
/* Now for some ELF specific code. FIXME. */
#ifdef OBJ_ELF
/* Mark the end of a function so that it's possible to compute
- the size of the function in hppa_elf_final_processing. */
+ the size of the function in elf_hppa_final_processing. */
static void
hppa_elf_mark_end_of_function ()