* xcofflink.c: (xcoff_mark_symbol): Mark the TOC section when
	creating a descriptor.
	(xcoff_sweep): Don't mark toc_section unless it's needed.
	(bfd_xcoff_size_dynamic_sections): Skip the toc_section
	when marking every bfd.
	(xcoff_link_input_bfd): Skip all TOC anchors.
	(xcoff_toc_section_p, xcoff_find_tc0): New functions.
	(_bfd_xcoff_bfd_final_link): Don't set the output bfd's TOC anchor
	to -1; call xcoff_find_tc0 instead.

ld/testsuite/
	* ld-powerpc/aix-toc-1.ex, ld-powerpc/aix-toc-1a.s,
	ld-powerpc/aix-toc-1b.s, ld-powerpc/aix-toc-1-32.dd,
	ld-powerpc/aix-toc-1-64.dd: New tests.
	* ld-powerpc/aix52.exp: Run them.
This commit is contained in:
Richard Sandiford 2009-03-14 09:18:22 +00:00
parent 4cc02a022b
commit 47dfb2ca05
9 changed files with 251 additions and 77 deletions

View file

@ -1,3 +1,15 @@
2009-03-14 Richard Sandiford <r.sandiford@uk.ibm.com>
* xcofflink.c: (xcoff_mark_symbol): Mark the TOC section when
creating a descriptor.
(xcoff_sweep): Don't mark toc_section unless it's needed.
(bfd_xcoff_size_dynamic_sections): Skip the toc_section
when marking every bfd.
(xcoff_link_input_bfd): Skip all TOC anchors.
(xcoff_toc_section_p, xcoff_find_tc0): New functions.
(_bfd_xcoff_bfd_final_link): Don't set the output bfd's TOC anchor
to -1; call xcoff_find_tc0 instead.
2009-03-14 Richard Sandiford <r.sandiford@uk.ibm.com> 2009-03-14 Richard Sandiford <r.sandiford@uk.ibm.com>
* libcoff-in.h (xcoff_section_tdata): Update commentary. * libcoff-in.h (xcoff_section_tdata): Update commentary.

View file

@ -2331,6 +2331,11 @@ xcoff_mark_symbol (struct bfd_link_info *info, struct xcoff_link_hash_entry *h)
if (!xcoff_mark_symbol (info, h->descriptor)) if (!xcoff_mark_symbol (info, h->descriptor))
return FALSE; return FALSE;
/* Mark the TOC section, so that we get an anchor
to relocate against. */
if (!xcoff_mark (info, xcoff_hash_table (info)->toc_section))
return FALSE;
/* We handle writing out the contents of the descriptor in /* We handle writing out the contents of the descriptor in
xcoff_write_global_symbol. */ xcoff_write_global_symbol. */
} }
@ -2590,7 +2595,6 @@ xcoff_sweep (struct bfd_link_info *info)
|| o == xcoff_hash_table (info)->debug_section || o == xcoff_hash_table (info)->debug_section
|| o == xcoff_hash_table (info)->loader_section || o == xcoff_hash_table (info)->loader_section
|| o == xcoff_hash_table (info)->linkage_section || o == xcoff_hash_table (info)->linkage_section
|| o == xcoff_hash_table (info)->toc_section
|| o == xcoff_hash_table (info)->descriptor_section || o == xcoff_hash_table (info)->descriptor_section
|| strcmp (o->name, ".debug") == 0) || strcmp (o->name, ".debug") == 0)
o->flags |= SEC_MARK; o->flags |= SEC_MARK;
@ -3126,7 +3130,12 @@ bfd_xcoff_size_dynamic_sections (bfd *output_bfd,
for (o = sub->sections; o != NULL; o = o->next) for (o = sub->sections; o != NULL; o = o->next)
{ {
if ((o->flags & SEC_MARK) == 0) /* We shouldn't unconditionaly mark the TOC section.
The output file should only have a TOC if either
(a) one of the input files did or (b) we end up
creating TOC references as part of the link process. */
if (o != xcoff_hash_table (info)->toc_section
&& (o->flags & SEC_MARK) == 0)
{ {
if (! xcoff_mark (info, o)) if (! xcoff_mark (info, o))
goto error_return; goto error_return;
@ -3504,7 +3513,6 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
union internal_auxent aux; union internal_auxent aux;
int smtyp = 0; int smtyp = 0;
bfd_boolean skip; bfd_boolean skip;
bfd_boolean require;
int add; int add;
bfd_coff_swap_sym_in (input_bfd, (void *) esym, (void *) isymp); bfd_coff_swap_sym_in (input_bfd, (void *) esym, (void *) isymp);
@ -3623,7 +3631,6 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
*indexp = -1; *indexp = -1;
skip = FALSE; skip = FALSE;
require = FALSE;
add = 1 + isym.n_numaux; add = 1 + isym.n_numaux;
/* If we are skipping this csect, we want to skip this symbol. */ /* If we are skipping this csect, we want to skip this symbol. */
@ -3644,75 +3651,11 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
&& isymp->n_sclass == C_STAT) && isymp->n_sclass == C_STAT)
skip = TRUE; skip = TRUE;
/* We skip all but the first TOC anchor. */ /* We generate the TOC anchor separately. */
if (! skip if (! skip
&& isymp->n_sclass == C_HIDEXT && isymp->n_sclass == C_HIDEXT
&& aux.x_csect.x_smclas == XMC_TC0) && aux.x_csect.x_smclas == XMC_TC0)
{ skip = TRUE;
if (finfo->toc_symindx != -1)
skip = TRUE;
else
{
bfd_vma tocval, tocend;
bfd *inp;
tocval = ((*csectpp)->output_section->vma
+ (*csectpp)->output_offset
+ isym.n_value
- (*csectpp)->vma);
/* We want to find out if tocval is a good value to use
as the TOC anchor--that is, whether we can access all
of the TOC using a 16 bit offset from tocval. This
test assumes that the TOC comes at the end of the
output section, as it does in the default linker
script. */
tocend = ((*csectpp)->output_section->vma
+ (*csectpp)->output_section->size);
for (inp = finfo->info->input_bfds;
inp != NULL;
inp = inp->link_next)
{
for (o = inp->sections; o != NULL; o = o->next)
if (strcmp (o->name, ".tocbss") == 0)
{
bfd_vma new_toc_end;
new_toc_end = (o->output_section->vma
+ o->output_offset
+ o->size);
if (new_toc_end > tocend)
tocend = new_toc_end;
}
}
if (tocval + 0x10000 < tocend)
{
(*_bfd_error_handler)
(_("TOC overflow: 0x%lx > 0x10000; try -mminimal-toc when compiling"),
(unsigned long) (tocend - tocval));
bfd_set_error (bfd_error_file_too_big);
return FALSE;
}
if (tocval + 0x8000 < tocend)
{
bfd_vma tocadd;
tocadd = tocend - (tocval + 0x8000);
tocval += tocadd;
isym.n_value += tocadd;
}
finfo->toc_symindx = output_index;
xcoff_data (finfo->output_bfd)->toc = tocval;
xcoff_data (finfo->output_bfd)->sntoc =
(*csectpp)->output_section->target_index;
require = TRUE;
}
}
/* If we are stripping all symbols, we want to skip this one. */ /* If we are stripping all symbols, we want to skip this one. */
if (! skip if (! skip
@ -3781,12 +3724,6 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
skip = TRUE; skip = TRUE;
} }
/* We can not skip the first TOC anchor. */
if (skip
&& require
&& finfo->info->strip != strip_all)
skip = FALSE;
/* We now know whether we are to skip this symbol or not. */ /* We now know whether we are to skip this symbol or not. */
if (! skip) if (! skip)
{ {
@ -4616,6 +4553,144 @@ xcoff_sort_relocs (const void * p1, const void * p2)
return 0; return 0;
} }
/* Return true if section SEC is a TOC section. */
static inline bfd_boolean
xcoff_toc_section_p (asection *sec)
{
const char *name;
name = sec->name;
if (name[0] == '.' && name[1] == 't')
{
if (name[2] == 'c')
{
if (name[3] == '0' && name[4] == 0)
return TRUE;
if (name[3] == 0)
return TRUE;
}
if (name[2] == 'd' && name[3] == 0)
return TRUE;
}
return FALSE;
}
/* See if the link requires a TOC (it usually does!). If so, find a
good place to put the TOC anchor csect, and write out the associated
symbol. */
static bfd_boolean
xcoff_find_tc0 (bfd *output_bfd, struct xcoff_final_link_info *finfo)
{
bfd_vma toc_start, toc_end, start, end, best_address;
asection *sec;
bfd *input_bfd;
int section_index;
struct internal_syment irsym;
union internal_auxent iraux;
file_ptr pos;
size_t size;
/* Set [TOC_START, TOC_END) to the range of the TOC. Record the
index of a csect at the beginning of the TOC. */
toc_start = ~(bfd_vma) 0;
toc_end = 0;
section_index = -1;
for (input_bfd = finfo->info->input_bfds;
input_bfd != NULL;
input_bfd = input_bfd->link_next)
for (sec = input_bfd->sections; sec != NULL; sec = sec->next)
if ((sec->flags & SEC_MARK) != 0 && xcoff_toc_section_p (sec))
{
start = sec->output_section->vma + sec->output_offset;
if (toc_start > start)
{
toc_start = start;
section_index = sec->output_section->target_index;
}
end = start + sec->size;
if (toc_end < end)
toc_end = end;
}
/* There's no need for a TC0 symbol if we don't have a TOC. */
if (toc_end < toc_start)
{
xcoff_data (output_bfd)->toc = toc_start;
return TRUE;
}
if (toc_end - toc_start < 0x8000)
/* Every TOC csect can be accessed from TOC_START. */
best_address = toc_start;
else
{
/* Find the lowest TOC csect that is still within range of TOC_END. */
best_address = toc_end;
for (input_bfd = finfo->info->input_bfds;
input_bfd != NULL;
input_bfd = input_bfd->link_next)
for (sec = input_bfd->sections; sec != NULL; sec = sec->next)
if ((sec->flags & SEC_MARK) != 0 && xcoff_toc_section_p (sec))
{
start = sec->output_section->vma + sec->output_offset;
if (start < best_address
&& start + 0x8000 >= toc_end)
{
best_address = start;
section_index = sec->output_section->target_index;
}
}
/* Make sure that the start of the TOC is also within range. */
if (best_address > toc_start + 0x8000)
{
(*_bfd_error_handler)
(_("TOC overflow: 0x%lx > 0x10000; try -mminimal-toc "
"when compiling"),
(unsigned long) (toc_end - toc_start));
bfd_set_error (bfd_error_file_too_big);
return FALSE;
}
}
/* Record the chosen TOC value. */
finfo->toc_symindx = obj_raw_syment_count (output_bfd);
xcoff_data (output_bfd)->toc = best_address;
xcoff_data (output_bfd)->sntoc = section_index;
/* Fill out the TC0 symbol. */
if (!bfd_xcoff_put_symbol_name (output_bfd, finfo->strtab, &irsym, "TOC"))
return FALSE;
irsym.n_value = best_address;
irsym.n_scnum = section_index;
irsym.n_sclass = C_HIDEXT;
irsym.n_type = T_NULL;
irsym.n_numaux = 1;
bfd_coff_swap_sym_out (output_bfd, &irsym, finfo->outsyms);
/* Fill out the auxillary csect information. */
memset (&iraux, 0, sizeof iraux);
iraux.x_csect.x_smtyp = XTY_SD;
iraux.x_csect.x_smclas = XMC_TC0;
iraux.x_csect.x_scnlen.l = 0;
bfd_coff_swap_aux_out (output_bfd, &iraux, T_NULL, C_HIDEXT, 0, 1,
finfo->outsyms + bfd_coff_symesz (output_bfd));
/* Write the contents to the file. */
pos = obj_sym_filepos (output_bfd);
pos += obj_raw_syment_count (output_bfd) * bfd_coff_symesz (output_bfd);
size = 2 * bfd_coff_symesz (output_bfd);
if (bfd_seek (output_bfd, pos, SEEK_SET) != 0
|| bfd_bwrite (finfo->outsyms, size, output_bfd) != size)
return FALSE;
obj_raw_syment_count (output_bfd) += 2;
return TRUE;
}
/* Write out a non-XCOFF global symbol. */ /* Write out a non-XCOFF global symbol. */
static bfd_boolean static bfd_boolean
@ -5692,7 +5767,10 @@ _bfd_xcoff_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
goto error_return; goto error_return;
obj_raw_syment_count (abfd) = 0; obj_raw_syment_count (abfd) = 0;
xcoff_data (abfd)->toc = (bfd_vma) -1;
/* Find a TOC symbol, if we need one. */
if (!xcoff_find_tc0 (abfd, &finfo))
goto error_return;
/* We now know the position of everything in the file, except that /* We now know the position of everything in the file, except that
we don't know the size of the symbol table and therefore we don't we don't know the size of the symbol table and therefore we don't

View file

@ -1,3 +1,10 @@
2009-03-14 Richard Sandiford <r.sandiford@uk.ibm.com>
* ld-powerpc/aix-toc-1.ex, ld-powerpc/aix-toc-1a.s,
ld-powerpc/aix-toc-1b.s, ld-powerpc/aix-toc-1-32.dd,
ld-powerpc/aix-toc-1-64.dd: New tests.
* ld-powerpc/aix52.exp: Run them.
2009-03-14 Richard Sandiford <r.sandiford@uk.ibm.com> 2009-03-14 Richard Sandiford <r.sandiford@uk.ibm.com>
* ld-powerpc/aix-glink-1.ex, ld-powerpc/aix-glink-1.s, * ld-powerpc/aix-glink-1.ex, ld-powerpc/aix-glink-1.s,

View file

@ -0,0 +1,12 @@
.*
Disassembly of section \.text:
10000000 <\.f1>:
10000000: 80 22 80 08 l r1,-32760\(r2\)
10000002: R_TOC sym0.*
#...
1000fff4: 80 22 7f fc l r1,32764\(r2\)
1000fff6: R_TOC asym8190.*

View file

@ -0,0 +1,12 @@
.*
Disassembly of section \.text:
0000000010000000 <.f1>:
10000000: e8 22 80 10 ld r1,-32752\(r2\)
10000002: R_TOC sym0.*
#...
10007ff4: e8 22 7f f8 ld r1,32760\(r2\)
10007ff6: R_TOC asym4094.*

View file

@ -0,0 +1,2 @@
f1
f2

View file

@ -0,0 +1,23 @@
.macro loadtoc
.toc
.tc sym\@[TC], \@
.csect .f1[PR]
.if size == 32
lwz 1,sym\@[TC](2)
.else
ld 1,sym\@[TC](2)
.endif
.endm
.globl .f1
.csect .f1[PR]
.f1:
.rept 0x7ffc * 8 / size
loadtoc
.endr
.globl f1
.csect f1[DS]
f1:
.long .f1[PR],TOC[TC0],0

View file

@ -0,0 +1,23 @@
.macro loadtoc
.toc
.tc asym\@[TC], \@ | 0x10000
.csect .f2[PR]
.if size == 32
lwz 1,asym\@[TC](2)
.else
ld 1,asym\@[TC](2)
.endif
.endm
.globl .f2
.csect .f2[PR]
.f2:
.rept 0x7ffc * 8 / size
loadtoc
.endr
.globl f2
.csect f2[DS]
f2:
.long .f2[PR],TOC[TC0],0

View file

@ -97,6 +97,11 @@ set aix52tests {
"" {aix-glink-1.s} "" {aix-glink-1.s}
{{objdump {-D -j.text -j.data} aix-glink-1-SIZE.dd}} {{objdump {-D -j.text -j.data} aix-glink-1-SIZE.dd}}
"aix-glink-1.so"} "aix-glink-1.so"}
{"TOC test 1" "-shared -bE:aix-toc-1.ex"
"" {aix-toc-1a.s aix-toc-1b.s}
{{objdump -dr aix-toc-1-SIZE.dd}}
"aix-toc-1.so"}
} }
foreach test $aix52tests { foreach test $aix52tests {