* 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>
* 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))
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
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)->loader_section
|| o == xcoff_hash_table (info)->linkage_section
|| o == xcoff_hash_table (info)->toc_section
|| o == xcoff_hash_table (info)->descriptor_section
|| strcmp (o->name, ".debug") == 0)
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)
{
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))
goto error_return;
@ -3504,7 +3513,6 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
union internal_auxent aux;
int smtyp = 0;
bfd_boolean skip;
bfd_boolean require;
int add;
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;
skip = FALSE;
require = FALSE;
add = 1 + isym.n_numaux;
/* 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)
skip = TRUE;
/* We skip all but the first TOC anchor. */
/* We generate the TOC anchor separately. */
if (! skip
&& isymp->n_sclass == C_HIDEXT
&& aux.x_csect.x_smclas == XMC_TC0)
{
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;
}
}
skip = TRUE;
/* If we are stripping all symbols, we want to skip this one. */
if (! skip
@ -3781,12 +3724,6 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
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. */
if (! skip)
{
@ -4616,6 +4553,144 @@ xcoff_sort_relocs (const void * p1, const void * p2)
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. */
static bfd_boolean
@ -5692,7 +5767,10 @@ _bfd_xcoff_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
goto error_return;
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 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>
* 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}
{{objdump {-D -j.text -j.data} aix-glink-1-SIZE.dd}}
"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 {