summaryrefslogtreecommitdiff
path: root/gnu
diff options
context:
space:
mode:
authorkristerw <kristerw@NetBSD.org>1998-09-13 13:28:24 +0000
committerkristerw <kristerw@NetBSD.org>1998-09-13 13:28:24 +0000
commitb18f424e810c0dc52d76a361335da89cdbfd01a6 (patch)
tree6cef9900205b76c7ca177200257e32f4395eb584 /gnu
parent45935a4c8d5459a6a0972e191e25ab8d90f86b4c (diff)
Make gas generate our a.out format (for sparc and i386)
Diffstat (limited to 'gnu')
-rw-r--r--gnu/dist/gas/config/obj-aout.c174
-rw-r--r--gnu/dist/gas/config/obj-aout.h13
-rw-r--r--gnu/dist/gas/config/tc-i386.c78
-rw-r--r--gnu/dist/gas/config/tc-i386.h1
-rw-r--r--gnu/dist/gas/config/tc-sparc.c4
5 files changed, 264 insertions, 6 deletions
diff --git a/gnu/dist/gas/config/obj-aout.c b/gnu/dist/gas/config/obj-aout.c
index bb566e1e374..d487f466ad5 100644
--- a/gnu/dist/gas/config/obj-aout.c
+++ b/gnu/dist/gas/config/obj-aout.c
@@ -65,6 +65,9 @@ const segT N_TYPE_seg[N_TYPE + 2] =
static void obj_aout_line PARAMS ((int));
static void obj_aout_weak PARAMS ((int));
static void obj_aout_type PARAMS ((int));
+static void obj_aout_size PARAMS ((int));
+
+int aout_pic_flag = 0;
const pseudo_typeS obj_pseudo_table[] =
{
@@ -83,7 +86,7 @@ const pseudo_typeS obj_pseudo_table[] =
{"line", s_ignore, 0},
{"ln", s_ignore, 0},
{"scl", s_ignore, 0},
- {"size", s_ignore, 0},
+ {"size", obj_aout_size, 0},
{"tag", s_ignore, 0},
{"val", s_ignore, 0},
{"version", s_ignore, 0},
@@ -100,6 +103,54 @@ const pseudo_typeS obj_pseudo_table[] =
#ifdef BFD_ASSEMBLER
void
+obj_aout_add_size_symbols()
+{
+ /* We don't generate N_SIZE symbols unless we are working with PIC code. */
+ if (!aout_pic_flag)
+ return;
+
+ if (symbol_rootP)
+ {
+ symbolS *sym;
+
+ for (sym = symbol_rootP; sym; sym = symbol_next (sym))
+ {
+ int type, other;
+
+ type = S_GET_TYPE (sym);
+ other = S_GET_OTHER (sym);
+
+ /* We do only add SIZE symbols for objects (i.e other == 1)
+ that have a .size directive. */
+ if ((type != N_SIZE)
+ && (type != (N_SIZE | N_EXT))
+ && (other == 1)
+ && ((expressionS*)sym->sy_sizexp != NULL))
+ {
+ expressionS *exp = (expressionS*)sym->sy_sizexp;
+ symbolS *new_sym;
+ int new_type;
+ long size;
+
+ new_type = N_SIZE;
+
+ if (type && N_EXT)
+ new_type |= N_EXT;
+
+ new_sym = symbol_make(S_GET_NAME(sym));
+ S_SET_TYPE(new_sym, new_type);
+ new_sym->bsym->section = bfd_abs_section_ptr;
+ new_sym->bsym->flags = sym->bsym->flags;
+
+ size = exp->X_add_number;
+
+ S_SET_VALUE(new_sym,size);
+ }
+ }
+ }
+}
+
+void
obj_aout_frob_symbol (sym, punt)
symbolS *sym;
int *punt;
@@ -213,6 +264,14 @@ obj_aout_frob_file ()
(bfd_size_type) 1);
}
assert (x == true);
+
+ /* Some archetectures has a 'pic' flag in their a.out header. I'm not
+ sure this is the right place to set it, but this is the best hook
+ I have found... */
+ if (aout_pic_flag)
+ {
+ stdoutput->flags = BFD_PIC;
+ }
}
#else
@@ -390,7 +449,7 @@ obj_aout_weak (ignore)
/* Handle .type. On {Net,Open}BSD, this is used to set the n_other field,
which is then apparently used when doing dynamic linking. Older
- versions ogas ignored the .type pseudo-op, so we also ignore it if
+ versions of gas ignored the .type pseudo-op, so we also ignore it if
we can't parse it. */
static void
@@ -403,7 +462,7 @@ obj_aout_type (ignore)
name = input_line_pointer;
c = get_symbol_end ();
- sym = symbol_find (name);
+ sym = symbol_find_or_make (name);
*input_line_pointer = c;
if (sym != NULL)
{
@@ -626,4 +685,113 @@ DEFUN_VOID (s_sect)
#endif /* ! BFD_ASSEMBLER */
+static segT
+get_segmented_expression (expP)
+ register expressionS *expP;
+{
+ register segT retval;
+
+ retval = expression (expP);
+ if (expP->X_op == O_illegal
+ || expP->X_op == O_absent
+ || expP->X_op == O_big)
+ {
+ as_bad ("expected address expression; zero assumed");
+ expP->X_op = O_constant;
+ expP->X_add_number = 0;
+ retval = absolute_section;
+ }
+
+ return retval;
+}
+
+static segT
+get_known_segmented_expression (expP)
+ register expressionS *expP;
+{
+ register segT retval;
+
+ if ((retval = get_segmented_expression (expP)) == undefined_section)
+ {
+ /* There is no easy way to extract the undefined symbol from the
+ expression. */
+ if (expP->X_add_symbol != NULL
+ && S_GET_SEGMENT (expP->X_add_symbol) != expr_section)
+ as_warn ("symbol \"%s\" undefined; zero assumed",
+ S_GET_NAME (expP->X_add_symbol));
+ else
+ as_warn ("some symbol undefined; zero assumed");
+ retval = absolute_section;
+ expP->X_op = O_constant;
+ expP->X_add_number = 0;
+ }
+
+ know (retval == absolute_section || SEG_NORMAL (retval));
+ return (retval);
+} /* get_known_segmented_expression() */
+
+static void obj_aout_size(ignore)
+ int ignore;
+{
+ register char *name;
+ register char c;
+ register char *p;
+ register int temp;
+ register symbolS *symbolP;
+ expressionS *exp;
+ segT seg;
+ segT retval;
+
+ /* SIZE_T is only used in PIC code. */
+ if (!aout_pic_flag)
+ {
+ s_ignore(0);
+ return;
+ }
+
+ SKIP_WHITESPACE();
+ name = input_line_pointer;
+ c = get_symbol_end();
+ /* just after name is now '\0' */
+ symbolP = symbol_find(name);
+ p = input_line_pointer;
+ *p = c;
+
+ if (symbolP == NULL || (S_GET_OTHER(symbolP) != 1))
+ {
+ /* Not an object. Ignore. */
+ /* XXX This assumes that the symbol is created before the .size
+ directive. */
+ s_ignore(0);
+ return;
+ }
+
+ SKIP_WHITESPACE();
+ if (*input_line_pointer != ',')
+ {
+ as_bad("Expected comma after symbol-name: rest of line ignored.");
+ ignore_rest_of_line();
+ return;
+ }
+ input_line_pointer ++; /* skip ',' */
+ exp = (expressionS *)xmalloc(sizeof(expressionS));
+ retval = get_known_segmented_expression(exp);
+ if (retval != absolute_section)
+ {
+ as_bad("Illegal .size expression");
+ ignore_rest_of_line();
+ return;
+ }
+
+ *p = 0;
+ symbolP = symbol_find_or_make(name);
+ *p = c;
+ if (symbolP->sy_sizexp) {
+ as_warn("\"%s\" already has a size", S_GET_NAME(symbolP));
+ } else
+ symbolP->sy_sizexp = (void *)exp;
+
+ demand_empty_rest_of_line();
+} /* obj_aout_size() */
+
/* end of obj-aout.c */
diff --git a/gnu/dist/gas/config/obj-aout.h b/gnu/dist/gas/config/obj-aout.h
index ab47ab653a3..90099a5a815 100644
--- a/gnu/dist/gas/config/obj-aout.h
+++ b/gnu/dist/gas/config/obj-aout.h
@@ -232,4 +232,17 @@ void tc_aout_fix_to_chars PARAMS ((char *where, struct fix *fixP, relax_addressT
#define AOUT_STABS
+extern int aout_pic_flag;
+
+#ifdef TE_NetBSD
+extern void obj_aout_add_size_symbols PARAMS ((void));
+#define TARGET_SYMBOL_FIELDS expressionS *sy_sizexp;
+#define obj_frob_file_before_adjust() obj_aout_add_size_symbols ()
+
+/* XXX This isn't the right thing to do... */
+#define obj_fix_adjustable(X) (!(aout_pic_flag \
+ && (S_IS_EXTERNAL (sym)) \
+ && (strcmp(".data", sec->name) == 0)))
+#endif /* TE_NetBSD */
+
/* end of obj-aout.h */
diff --git a/gnu/dist/gas/config/tc-i386.c b/gnu/dist/gas/config/tc-i386.c
index 3981a2d73a1..8b78a8383f8 100644
--- a/gnu/dist/gas/config/tc-i386.c
+++ b/gnu/dist/gas/config/tc-i386.c
@@ -2342,8 +2342,19 @@ i386_operand (operand_string)
if ((cp = strchr (input_line_pointer,'@')) != NULL) {
char tmpbuf[BUFSIZ];
- if(!GOT_symbol)
+ if(!GOT_symbol) {
+#if defined(TE_NetBSD) && defined(OBJ_AOUT)
+ /* gcc generates _GLOBAL_OFFSET_TABLE_, but an old
+ sun ld, that NetBSD by some reason wanted to be comatible
+ with, expexcted __GLOBAL_OFFSET_TABLE_. The problem
+ was solved this way in NetBSD's old gas. It should
+ probably be dealt with in libbfd... */
+ GOT_symbol
+ = symbol_find_or_make(NBSD_GLOBAL_OFFSET_TABLE_NAME);
+#else
GOT_symbol = symbol_find_or_make(GLOBAL_OFFSET_TABLE_NAME);
+#endif
+ }
if (strncmp(cp+1, "PLT", 3) == 0) {
i.disp_reloc[this_operand] = BFD_RELOC_386_PLT32;
@@ -2371,6 +2382,7 @@ i386_operand (operand_string)
#endif
exp_seg = expression (exp);
+#if !(defined(TE_NetBSD) && defined(OBJ_AOUT)) /* XXX */
#ifdef BFD_ASSEMBLER
/* We do this to make sure that the section symbol is in
the symbol table. We will ultimately change the relocation
@@ -2386,6 +2398,7 @@ i386_operand (operand_string)
i.disp_reloc[this_operand] = BFD_RELOC_32;
}
#endif
+#endif
if (*input_line_pointer)
as_bad ("Ignoring junk '%s' after expression", input_line_pointer);
@@ -2710,6 +2723,39 @@ md_apply_fix3 (fixP, valp, seg)
/* Fix a few things - the dynamic linker expects certain values here,
and we must not dissappoint it. */
+#if defined(TE_NetBSD) && defined(OBJ_AOUT)
+ if (fixP->fx_r_type == BFD_RELOC_32
+ && GOT_symbol
+ && fixP->fx_addsy == GOT_symbol)
+ {
+ fixP->fx_r_type = BFD_RELOC_386_GOTPC;
+ value += 1;
+ }
+ else if ((fixP->fx_r_type == BFD_RELOC_32)
+ && aout_pic_flag
+ && ((fixP->fx_addsy->bsym->flags & BSF_GLOBAL) != 0))
+ {
+ if (!bfd_is_com_section(bfd_get_section(fixP->fx_addsy->bsym)))
+ value = fixP->fx_offset - bfd_asymbol_value(fixP->fx_addsy->bsym);
+ }
+
+ switch(fixP->fx_r_type) {
+ case BFD_RELOC_386_PLT32:
+ break;
+ case BFD_RELOC_386_GOT32:
+ value = fixP->fx_offset;
+ break;
+ case BFD_RELOC_386_GOTPC:
+ value -= (fixP->fx_where + fixP->fx_frag->fr_address + 1);
+ break;
+ case BFD_RELOC_386_GOTOFF:
+ value = fixP->fx_offset;
+ break;
+
+ default:
+ break;
+ }
+#endif
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
if (OUTPUT_FLAVOR == bfd_target_elf_flavour
&& fixP->fx_addsy)
@@ -2883,7 +2929,7 @@ parse_register (reg_string)
#ifdef OBJ_ELF
CONST char *md_shortopts = "kmVQ:";
#else
-CONST char *md_shortopts = "m";
+CONST char *md_shortopts = "mkK";
#endif
struct option md_longopts[] = {
{NULL, no_argument, NULL, 0}
@@ -2916,6 +2962,12 @@ md_parse_option (c, arg)
case 'Q':
break;
#endif
+#ifdef OBJ_AOUT
+ case 'k':
+ case 'K':
+ aout_pic_flag = 1;
+ break;
+#endif
default:
return 0;
@@ -2968,8 +3020,19 @@ md_undefined_symbol (name)
{
if(symbol_find(name))
as_bad("GOT already in symbol table");
+#if defined(TE_NetBSD) && defined(OBJ_AOUT)
+ /* gcc generates _GLOBAL_OFFSET_TABLE_, but an old
+ sun ld, that NetBSD by some reason wanted to be comatible
+ with, expexcted __GLOBAL_OFFSET_TABLE_. The problem
+ was solved this way in NetBSD's old gas. It should
+ probably be dealt with in libbfd... */
+ GOT_symbol = symbol_new (NBSD_GLOBAL_OFFSET_TABLE_NAME,
+ undefined_section,
+ (valueT) 0, &zero_address_frag);
+#else
GOT_symbol = symbol_new (name, undefined_section,
(valueT) 0, &zero_address_frag);
+#endif
};
return GOT_symbol;
}
@@ -3052,6 +3115,17 @@ tc_gen_reloc (section, fixp)
switch(fixp->fx_r_type)
{
case BFD_RELOC_386_PLT32:
+#if defined(TE_NetBSD) && defined(OBJ_AOUT)
+ /* XXX */
+ if (fixp->fx_addsy != NULL)
+ {
+ asection *sec;
+ sec = bfd_get_section (fixp->fx_addsy->bsym);
+ if (strcmp(sec->name, ".text") == 0)
+ return 0;
+ }
+#endif
+ /* FALLTHROUGH */
case BFD_RELOC_386_GOT32:
case BFD_RELOC_386_GOTOFF:
case BFD_RELOC_386_GOTPC:
diff --git a/gnu/dist/gas/config/tc-i386.h b/gnu/dist/gas/config/tc-i386.h
index 8205f532054..e0a055d57dd 100644
--- a/gnu/dist/gas/config/tc-i386.h
+++ b/gnu/dist/gas/config/tc-i386.h
@@ -382,6 +382,7 @@ base_index_byte;
#ifndef GLOBAL_OFFSET_TABLE_NAME
#define GLOBAL_OFFSET_TABLE_NAME "_GLOBAL_OFFSET_TABLE_"
#endif
+#define NBSD_GLOBAL_OFFSET_TABLE_NAME "__GLOBAL_OFFSET_TABLE_"
#ifdef BFD_ASSEMBLER
void i386_validate_fix PARAMS ((struct fix *));
diff --git a/gnu/dist/gas/config/tc-sparc.c b/gnu/dist/gas/config/tc-sparc.c
index 2efad68e122..886b88e36d6 100644
--- a/gnu/dist/gas/config/tc-sparc.c
+++ b/gnu/dist/gas/config/tc-sparc.c
@@ -2846,7 +2846,7 @@ print_insn (insn)
CONST char *md_shortopts = "A:K:VQ:sq";
#else
#ifdef OBJ_AOUT
-CONST char *md_shortopts = "A:k";
+CONST char *md_shortopts = "A:kK";
#else
CONST char *md_shortopts = "A:";
#endif
@@ -2935,6 +2935,8 @@ md_parse_option (c, arg)
#ifdef OBJ_AOUT
case 'k':
+ case 'K':
+ aout_pic_flag = 1;
sparc_pic_code = 1;
break;
#endif