Commit 05e9452c authored by Alan Modra's avatar Alan Modra

* doc/as.texinfo (Reloc): Document.

	* read.c (potable): Add "reloc".
	(s_reloc): New function.
	* write.c (reloc_list): New global var.
	(resolve_reloc_expr_symbols): New function.
	(write_object_file): Call it.
	(write_relocs): Process reloc_list.
	* write.h (struct reloc_list): New.
	(reloc_list): Declare.
parent 157090f7
2007-03-26 Alan Modra <amodra@bigpond.net.au>
* doc/as.texinfo (Reloc): Document.
* read.c (potable): Add "reloc".
(s_reloc): New function.
* write.c (reloc_list): New global var.
(resolve_reloc_expr_symbols): New function.
(write_object_file): Call it.
(write_relocs): Process reloc_list.
* write.h (struct reloc_list): New.
(reloc_list): Declare.
2007-03-24 Paul Brook <paul@codesourcery.com>
* config/tc-arm.c (do_t_ldmstm): Error on Thumb-2 addressing modes.
......
......@@ -3886,6 +3886,7 @@ Some machine configurations provide additional directives.
@end ifset
* Quad:: @code{.quad @var{bignums}}
* Reloc:: @code{.reloc @var{offset}, @var{reloc_name}[, @var{expression}]}
* Rept:: @code{.rept @var{count}}
* Sbttl:: @code{.sbttl "@var{subheading}"}
@ifset COFF
......@@ -5433,6 +5434,20 @@ warning message; and just takes the lowest order 16 bytes of the bignum.
@cindex integer, 16-byte
@end ifset
@node Reloc
@section @code{.reloc @var{offset}, @var{reloc_name}[, @var{expression}]}
@cindex @code{reloc} directive
Generate a relocation at @var{offset} of type @var{reloc_name} with value
@var{expression}. If @var{offset} is a number, the relocation is generated in
the current section. If @var{offset} is an expression that resolves to a
symbol plus offset, the relocation is generated in the given symbol's section.
@var{expression}, if present, must resolve to a symbol plus addend or to an
absolute value, but note that not all targets support an addend. e.g. ELF REL
targets such as i386 store an addend in the section contents rather than in the
relocation. This low level interface does not support addends stored in the
section.
@node Rept
@section @code{.rept @var{count}}
......
......@@ -213,6 +213,7 @@ static void do_align (int, char *, int, int);
static void s_align (int, int);
static void s_altmacro (int);
static void s_bad_end (int);
static void s_reloc (int);
static int hex_float (int, char *);
static segT get_known_segmented_expression (expressionS * expP);
static void pobegin (void);
......@@ -391,6 +392,7 @@ static const pseudo_typeS potable[] = {
{"psize", listing_psize, 0}, /* Set paper size. */
{"purgem", s_purgem, 0},
{"quad", cons, 8},
{"reloc", s_reloc, 0},
{"rep", s_rept, 0},
{"rept", s_rept, 0},
{"rva", s_rva, 4},
......@@ -3669,6 +3671,113 @@ s_rva (int size)
cons_worker (size, 1);
}
/* .reloc offset, reloc_name, symbol+addend. */
void
s_reloc (int ignore ATTRIBUTE_UNUSED)
{
char *stop = NULL;
char stopc = 0;
expressionS exp;
char *r_name;
int c;
struct reloc_list *reloc;
reloc = xmalloc (sizeof (*reloc));
if (flag_mri)
stop = mri_comment_field (&stopc);
expression (&exp);
switch (exp.X_op)
{
case O_illegal:
case O_absent:
case O_big:
case O_register:
as_bad (_("missing or bad offset expression"));
goto err_out;
case O_constant:
exp.X_add_symbol = section_symbol (now_seg);
exp.X_op = O_symbol;
/* Fall thru */
case O_symbol:
if (exp.X_add_number == 0)
{
reloc->u.a.offset_sym = exp.X_add_symbol;
break;
}
/* Fall thru */
default:
reloc->u.a.offset_sym = make_expr_symbol (&exp);
break;
}
SKIP_WHITESPACE ();
if (*input_line_pointer != ',')
{
as_bad (_("missing reloc type"));
goto err_out;
}
++input_line_pointer;
SKIP_WHITESPACE ();
r_name = input_line_pointer;
c = get_symbol_end ();
reloc->u.a.howto = bfd_reloc_name_lookup (stdoutput, r_name);
*input_line_pointer = c;
if (reloc->u.a.howto == NULL)
{
as_bad (_("unrecognized reloc type"));
goto err_out;
}
exp.X_op = O_absent;
SKIP_WHITESPACE ();
if (*input_line_pointer == ',')
{
++input_line_pointer;
expression_and_evaluate (&exp);
}
switch (exp.X_op)
{
case O_illegal:
case O_big:
case O_register:
as_bad (_("bad reloc expression"));
err_out:
ignore_rest_of_line ();
free (reloc);
if (flag_mri)
mri_comment_end (stop, stopc);
return;
case O_absent:
reloc->u.a.sym = NULL;
reloc->u.a.addend = 0;
break;
case O_constant:
reloc->u.a.sym = NULL;
reloc->u.a.addend = exp.X_add_number;
break;
case O_symbol:
reloc->u.a.sym = exp.X_add_symbol;
reloc->u.a.addend = exp.X_add_number;
break;
default:
reloc->u.a.sym = make_expr_symbol (&exp);
reloc->u.a.addend = 0;
break;
}
as_where (&reloc->file, &reloc->line);
reloc->next = reloc_list;
reloc_list = reloc;
demand_empty_rest_of_line ();
if (flag_mri)
mri_comment_end (stop, stopc);
}
/* Put the contents of expression EXP into the object file using
NBYTES bytes. If need_pass_2 is 1, this does nothing. */
......
......@@ -117,6 +117,9 @@ symbolS *abs_section_sym;
/* Remember the value of dot when parsing expressions. */
addressT dot_value;
/* Relocs generated by ".reloc" pseudo. */
struct reloc_list* reloc_list;
void print_fixup (fixS *);
/* We generally attach relocs to frag chains. However, after we have
......@@ -624,6 +627,86 @@ dump_section_relocs (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, FILE *stream)
#define EMIT_SECTION_SYMBOLS 1
#endif
/* Resolve U.A.OFFSET_SYM and U.A.SYM fields of RELOC_LIST entries,
and check for validity. Convert RELOC_LIST from using U.A fields
to U.B fields. */
static void
resolve_reloc_expr_symbols (void)
{
struct reloc_list *r;
for (r = reloc_list; r; r = r->next)
{
expressionS *symval;
symbolS *sym;
bfd_vma offset, addend;
asection *sec;
reloc_howto_type *howto;
resolve_symbol_value (r->u.a.offset_sym);
symval = symbol_get_value_expression (r->u.a.offset_sym);
offset = 0;
sym = NULL;
if (symval->X_op == O_constant)
sym = r->u.a.offset_sym;
else if (symval->X_op == O_symbol)
{
sym = symval->X_add_symbol;
offset = symval->X_add_number;
symval = symbol_get_value_expression (symval->X_add_symbol);
}
if (sym == NULL
|| symval->X_op != O_constant
|| (sec = S_GET_SEGMENT (sym)) == NULL
|| !SEG_NORMAL (sec))
{
as_bad_where (r->file, r->line, _("invalid offset expression"));
sec = NULL;
}
else
offset += S_GET_VALUE (sym);
sym = NULL;
addend = r->u.a.addend;
if (r->u.a.sym != NULL)
{
resolve_symbol_value (r->u.a.sym);
symval = symbol_get_value_expression (r->u.a.sym);
if (symval->X_op == O_constant)
sym = r->u.a.sym;
else if (symval->X_op == O_symbol)
{
sym = symval->X_add_symbol;
addend += symval->X_add_number;
symval = symbol_get_value_expression (symval->X_add_symbol);
}
if (symval->X_op != O_constant)
{
as_bad_where (r->file, r->line, _("invalid reloc expression"));
sec = NULL;
}
else if (sym != NULL)
symbol_mark_used_in_reloc (sym);
}
if (sym == NULL)
{
if (abs_section_sym == NULL)
abs_section_sym = section_symbol (absolute_section);
sym = abs_section_sym;
}
howto = r->u.a.howto;
r->u.b.sec = sec;
r->u.b.s = symbol_get_bfdsym (sym);
r->u.b.r.sym_ptr_ptr = &r->u.b.s;
r->u.b.r.address = offset;
r->u.b.r.addend = addend;
r->u.b.r.howto = howto;
}
}
/* This pass over fixups decides whether symbols can be replaced with
section symbols. */
......@@ -1027,6 +1110,7 @@ write_relocs (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
segment_info_type *seginfo = seg_info (sec);
unsigned int i;
unsigned int n;
struct reloc_list *my_reloc_list, **rp, *r;
arelent **relocs;
fixS *fixp;
......@@ -1044,6 +1128,22 @@ write_relocs (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
n *= MAX_RELOC_EXPANSION;
#endif
/* Extract relocs for this section from reloc_list. */
rp = &reloc_list;
my_reloc_list = NULL;
while ((r = *rp) != NULL)
{
if (r->u.b.sec == sec)
{
*rp = r->next;
r->next = my_reloc_list;
my_reloc_list = r;
n++;
}
else
rp = &r->next;
}
relocs = xcalloc (n, sizeof (arelent *));
i = 0;
......@@ -1107,6 +1207,23 @@ write_relocs (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
}
#endif
for (r = my_reloc_list; r != NULL; r = r->next)
{
fragS *f;
for (f = seginfo->frchainP->frch_root; f; f = f->fr_next)
if (f->fr_address <= r->u.b.r.address
&& r->u.b.r.address < f->fr_address + f->fr_fix)
break;
if (f == NULL)
as_bad_where (r->file, r->line,
_("reloc not within (fixed part of) section"));
else
{
relocs[n++] = &r->u.b.r;
install_reloc (sec, &r->u.b.r, f, r->file, r->line);
}
}
if (n)
{
flagword flags = bfd_get_section_flags (abfd, sec);
......@@ -1564,6 +1681,7 @@ write_object_file (void)
resolve_symbol_value (symp);
}
resolve_local_symbol_values ();
resolve_reloc_expr_symbols ();
PROGRESS (1);
......
......@@ -142,11 +142,35 @@ struct fix
typedef struct fix fixS;
struct reloc_list
{
struct reloc_list *next;
union
{
struct
{
symbolS *offset_sym;
reloc_howto_type *howto;
symbolS *sym;
bfd_vma addend;
} a;
struct
{
asection *sec;
asymbol *s;
arelent r;
} b;
} u;
char *file;
unsigned int line;
};
extern int finalize_syms;
extern symbolS *abs_section_sym;
extern addressT dot_value;
extern long string_byte_count;
extern int section_alignment[];
extern struct reloc_list* reloc_list;
extern void append (char **charPP, char *fromP, unsigned long length);
extern void record_alignment (segT seg, int align);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment