aboutsummaryrefslogtreecommitdiff
path: root/bfd/xcofflink.c
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@airs.com>1995-11-09 18:08:56 +0000
committerIan Lance Taylor <ian@airs.com>1995-11-09 18:08:56 +0000
commitee17481566f6be499901644030897308d18eb18f (patch)
treed3fca7da7786d67a29cb8e2f4f423bde89374886 /bfd/xcofflink.c
parent0e829f1854e395e990eec2c077cf0aa6d05e6c0e (diff)
downloadgdb-ee17481566f6be499901644030897308d18eb18f.zip
gdb-ee17481566f6be499901644030897308d18eb18f.tar.gz
gdb-ee17481566f6be499901644030897308d18eb18f.tar.bz2
* xcofflink.c (XCOFF_DESCRIPTOR): Define.
(struct xcoff_link_hash_table): Add descriptor_section and special_sections fields. (_bfd_xcoff_bfd_link_hash_table_create): Initialize new fields. (xcoff_link_add_symbols): Set linkage section alignment. Create descriptor section. Check for magic symbol names (_text, etc.), and record them in special_sections if found. Set XCOFF_DESCRIPTOR flag for a function descriptor, and set its descriptor field to point back to the function code symbol. (xcoff_sweep): Always mark the special descriptor_section. (bfd_xcoff_export_symbol): Check whether the symbol might be a function descriptor, and mark it if it is. (bfd_xcoff_size_dynamic_sections): Add new special_sections parameter, and fill it in. Allocate space for the descriptor section. (xcoff_build_ldsyms): Set XCOFF_DEF_REGULAR flag when defining global linkage code. If an undefined function descriptor is exported, arrange to define it. Warn about any other undefined exported symbol. (_bfd_xcoff_bfd_final_link): Write out the descriptor section. (xcoff_write_global_symbol): Create a function descriptor when necessary. * bfd-in.h (bfd_xcoff_size_dynamic_sections): Update declaration. * bfd-in2.h: Rebuild.
Diffstat (limited to 'bfd/xcofflink.c')
-rw-r--r--bfd/xcofflink.c289
1 files changed, 284 insertions, 5 deletions
diff --git a/bfd/xcofflink.c b/bfd/xcofflink.c
index fd1ed7e..ca0b27b 100644
--- a/bfd/xcofflink.c
+++ b/bfd/xcofflink.c
@@ -261,7 +261,9 @@ struct xcoff_link_hash_entry
} u;
/* If this symbol is a function entry point which is called, this
- field holds a pointer to the function descriptor. */
+ field holds a pointer to the function descriptor. If this symbol
+ is a function descriptor, this field holds a pointer to the
+ function entry point. */
struct xcoff_link_hash_entry *descriptor;
/* The .loader symbol table entry, if there is one. */
@@ -296,6 +298,8 @@ struct xcoff_link_hash_entry
#define XCOFF_MARK (02000)
/* Symbol size is recorded in size_list list from hash table. */
#define XCOFF_HAS_SIZE (04000)
+ /* Symbol is a function descriptor. */
+#define XCOFF_DESCRIPTOR (010000)
/* The storage mapping class. */
unsigned char smclas;
@@ -332,6 +336,10 @@ struct xcoff_link_hash_table
linkage code. */
asection *toc_section;
+ /* The .ds section we use to hold function descriptors which we
+ create for exported symbols. */
+ asection *descriptor_section;
+
/* The list of import files. */
struct xcoff_import_file *imports;
@@ -351,6 +359,9 @@ struct xcoff_link_hash_table
struct xcoff_link_hash_entry *h;
bfd_size_type size;
} *size_list;
+
+ /* Magic sections: _text, _etext, _data, _edata, _end, end. */
+ asection *special_sections[6];
};
/* Information we keep for each section in the output file during the
@@ -627,10 +638,12 @@ _bfd_xcoff_bfd_link_hash_table_create (abfd)
memset (&ret->ldhdr, 0, sizeof (struct internal_ldhdr));
ret->linkage_section = NULL;
ret->toc_section = NULL;
+ ret->descriptor_section = NULL;
ret->imports = NULL;
ret->file_align = 0;
ret->textro = false;
ret->gc = false;
+ memset (ret->special_sections, 0, sizeof ret->special_sections);
/* The linker will always generate a full a.out header. We need to
record that fact now, before the sizeof_headers routine could be
@@ -978,6 +991,7 @@ xcoff_link_add_symbols (abfd, info)
goto error_return;
xcoff_hash_table (info)->linkage_section = lsec;
lsec->flags |= SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY;
+ lsec->alignment_power = 2;
}
/* Likewise for the TOC section. */
if (xcoff_hash_table (info)->toc_section == NULL)
@@ -991,6 +1005,18 @@ xcoff_link_add_symbols (abfd, info)
tsec->flags |= SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY;
tsec->alignment_power = 2;
}
+ /* Likewise for the descriptor section. */
+ if (xcoff_hash_table (info)->descriptor_section == NULL)
+ {
+ asection *dsec;
+
+ dsec = bfd_make_section_anyway (abfd, ".ds");
+ if (dsec == NULL)
+ goto error_return;
+ xcoff_hash_table (info)->descriptor_section = dsec;
+ dsec->flags |= SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY;
+ dsec->alignment_power = 2;
+ }
/* Likewise for the .debug section. */
if (xcoff_hash_table (info)->debug_section == NULL)
{
@@ -1623,6 +1649,33 @@ xcoff_link_add_symbols (abfd, info)
break;
}
+ /* Check for magic symbol names. */
+ if ((smtyp == XTY_SD || smtyp == XTY_CM)
+ && aux.x_csect.x_smclas != XMC_TC)
+ {
+ int i;
+
+ i = -1;
+ if (name[0] == '_')
+ {
+ if (strcmp (name, "_text") == 0)
+ i = 0;
+ else if (strcmp (name, "_etext") == 0)
+ i = 1;
+ else if (strcmp (name, "_data") == 0)
+ i = 2;
+ else if (strcmp (name, "_edata") == 0)
+ i = 3;
+ else if (strcmp (name, "_end") == 0)
+ i = 4;
+ }
+ else if (name[0] == 'e' && strcmp (name, "end") == 0)
+ i = 5;
+
+ if (i != -1)
+ xcoff_hash_table (info)->special_sections[i] = csect;
+ }
+
/* Now we have enough information to add the symbol to the
linker hash table. */
@@ -1800,6 +1853,10 @@ xcoff_link_add_symbols (abfd, info)
(struct bfd_link_hash_entry **) &hds)))
goto error_return;
}
+ hds->flags |= XCOFF_DESCRIPTOR;
+ BFD_ASSERT ((hds->flags & XCOFF_CALLED) == 0
+ && (h->flags & XCOFF_DESCRIPTOR) == 0);
+ hds->descriptor = h;
h->descriptor = hds;
}
}
@@ -2250,6 +2307,7 @@ xcoff_sweep (info)
|| 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;
else
@@ -2411,10 +2469,51 @@ bfd_xcoff_export_symbol (output_bfd, info, harg, syscall)
/* FIXME: I'm not at all sure what syscall is supposed to mean, so
I'm just going to ignore it until somebody explains it. */
+ /* See if this is a function descriptor. It may be one even though
+ it is not so marked. */
+ if ((h->flags & XCOFF_DESCRIPTOR) == 0
+ && h->root.root.string[0] != '.')
+ {
+ char *fnname;
+ struct xcoff_link_hash_entry *hfn;
+
+ fnname = (char *) malloc (strlen (h->root.root.string + 2));
+ if (fnname == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ fnname[0] = '.';
+ strcpy (fnname + 1, h->root.root.string);
+ hfn = xcoff_link_hash_lookup (xcoff_hash_table (info),
+ fnname, false, false, true);
+ free (fnname);
+ if (hfn != NULL
+ && hfn->smclas == XMC_PR
+ && (hfn->root.type == bfd_link_hash_defined
+ || hfn->root.type == bfd_link_hash_defweak))
+ {
+ h->flags |= XCOFF_DESCRIPTOR;
+ h->descriptor = hfn;
+ hfn->descriptor = h;
+ }
+ }
+
/* Make sure we don't garbage collect this symbol. */
if (! xcoff_mark_symbol (info, h))
return false;
+ /* If this is a function descriptor, make sure we don't garbage
+ collect the associated function code. We normally don't have to
+ worry about this, because the descriptor will be attached to a
+ section with relocs, but if we are creating the descriptor
+ ourselves those relocs will not be visible to the mark code. */
+ if ((h->flags & XCOFF_DESCRIPTOR) != 0)
+ {
+ if (! xcoff_mark_symbol (info, h->descriptor))
+ return false;
+ }
+
return true;
}
@@ -2507,7 +2606,7 @@ struct xcoff_loader_info
boolean
bfd_xcoff_size_dynamic_sections (output_bfd, info, libpath, entry,
file_align, maxstack, maxdata, gc,
- modtype, textro)
+ modtype, textro, special_sections)
bfd *output_bfd;
struct bfd_link_info *info;
const char *libpath;
@@ -2518,10 +2617,12 @@ bfd_xcoff_size_dynamic_sections (output_bfd, info, libpath, entry,
boolean gc;
int modtype;
boolean textro;
+ asection **special_sections;
{
struct xcoff_link_hash_entry *hentry;
asection *lsec;
struct xcoff_loader_info ldinfo;
+ int i;
size_t impsize, impcount;
struct xcoff_import_file *fl;
struct internal_ldhdr *ldhdr;
@@ -2595,6 +2696,19 @@ bfd_xcoff_size_dynamic_sections (output_bfd, info, libpath, entry,
xcoff_hash_table (info)->gc = true;
}
+ /* Return special sections to the caller. */
+ for (i = 0; i < 6; i++)
+ {
+ asection *sec;
+
+ sec = xcoff_hash_table (info)->special_sections[i];
+ if (sec != NULL
+ && gc
+ && (sec->flags & SEC_MARK) == 0)
+ sec = NULL;
+ special_sections[i] = sec;
+ }
+
if (info->input_bfds == NULL)
{
/* I'm not sure what to do in this bizarre case. */
@@ -2694,8 +2808,7 @@ bfd_xcoff_size_dynamic_sections (output_bfd, info, libpath, entry,
when the corresponding normal relocs are handled in
xcoff_link_input_bfd. */
- /* Allocate space for the global linkage section and the global toc
- section. */
+ /* Allocate space for the magic sections. */
sec = xcoff_hash_table (info)->linkage_section;
if (sec->_raw_size > 0)
{
@@ -2716,6 +2829,16 @@ bfd_xcoff_size_dynamic_sections (output_bfd, info, libpath, entry,
goto error_return;
}
}
+ sec = xcoff_hash_table (info)->descriptor_section;
+ if (sec->_raw_size > 0)
+ {
+ sec->contents = (bfd_byte *) bfd_zalloc (output_bfd, sec->_raw_size);
+ if (sec->contents == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+ }
/* Now that we've done garbage collection, figure out the contents
of the .debug section. */
@@ -2877,6 +3000,7 @@ xcoff_build_ldsyms (h, p)
h->root.u.def.section = sec;
h->root.u.def.value = sec->_raw_size;
h->smclas = XMC_GL;
+ h->flags |= XCOFF_DEF_REGULAR;
sec->_raw_size += XCOFF_GLINK_SIZE;
/* The global linkage code requires a TOC entry for the
@@ -2902,6 +3026,53 @@ xcoff_build_ldsyms (h, p)
}
}
+ /* If this symbol is exported, but not defined, we need to try to
+ define it. */
+ if ((h->flags & XCOFF_EXPORT) != 0
+ && (h->flags & XCOFF_IMPORT) == 0
+ && (h->flags & XCOFF_DEF_REGULAR) == 0
+ && (h->flags & XCOFF_DEF_DYNAMIC) == 0
+ && (h->root.type == bfd_link_hash_undefined
+ || h->root.type == bfd_link_hash_undefweak))
+ {
+ if ((h->flags & XCOFF_DESCRIPTOR) != 0
+ && (h->descriptor->root.type == bfd_link_hash_defined
+ || h->descriptor->root.type == bfd_link_hash_defweak))
+ {
+ asection *sec;
+
+ /* This is an undefined function descriptor associated with
+ a defined entry point. We can build up a function
+ descriptor ourselves. Believe it or not, the AIX linker
+ actually does this, and there are cases where we need to
+ do it as well. */
+ sec = xcoff_hash_table (ldinfo->info)->descriptor_section;
+ h->root.type = bfd_link_hash_defined;
+ h->root.u.def.section = sec;
+ h->root.u.def.value = sec->_raw_size;
+ h->smclas = XMC_DS;
+ h->flags |= XCOFF_DEF_REGULAR;
+ sec->_raw_size += 12;
+
+ /* A function descriptor uses two relocs: one for the
+ associated code, and one for the TOC address. */
+ xcoff_hash_table (ldinfo->info)->ldrel_count += 2;
+ sec->reloc_count += 2;
+
+ /* We handle writing out the contents of the descriptor in
+ xcoff_write_global_symbol. */
+ }
+ else
+ {
+ (*_bfd_error_handler)
+ ("attempt to export undefined symbol `%s'",
+ h->root.root.string);
+ ldinfo->failed = true;
+ bfd_set_error (bfd_error_invalid_operation);
+ return false;
+ }
+ }
+
/* If this is still a common symbol, and it wasn't garbage
collected, we need to actually allocate space for it in the .bss
section. */
@@ -3528,7 +3699,7 @@ _bfd_xcoff_bfd_final_link (abfd, info)
o->_raw_size))
goto error_return;
- /* Write out the global linkage section and the toc section. */
+ /* Write out the magic sections. */
o = xcoff_hash_table (info)->linkage_section;
if (o->_raw_size > 0
&& ! bfd_set_section_contents (abfd, o->output_section, o->contents,
@@ -3539,6 +3710,11 @@ _bfd_xcoff_bfd_final_link (abfd, info)
&& ! bfd_set_section_contents (abfd, o->output_section, o->contents,
o->output_offset, o->_raw_size))
goto error_return;
+ o = xcoff_hash_table (info)->descriptor_section;
+ if (o->_raw_size > 0
+ && ! bfd_set_section_contents (abfd, o->output_section, o->contents,
+ o->output_offset, o->_raw_size))
+ goto error_return;
/* Write out the string table. */
if (bfd_seek (abfd,
@@ -4857,6 +5033,109 @@ xcoff_write_global_symbol (h, p)
++finfo->ldrel;
}
+ /* If this symbol is a specially defined function descriptor, write
+ it out. The first word is the address of the function code
+ itself, the second word is the address of the TOC, and the third
+ word is zero. */
+ if ((h->flags & XCOFF_DESCRIPTOR) != 0
+ && h->root.type == bfd_link_hash_defined
+ && (h->root.u.def.section
+ == xcoff_hash_table (finfo->info)->descriptor_section))
+ {
+ asection *sec;
+ asection *osec;
+ int oindx;
+ bfd_byte *p;
+ struct xcoff_link_hash_entry *hentry;
+ asection *esec;
+ struct internal_reloc *irel;
+ struct internal_ldrel ldrel;
+ asection *tsec;
+
+ sec = h->root.u.def.section;
+ osec = sec->output_section;
+ oindx = osec->target_index;
+ p = sec->contents + h->root.u.def.value;
+
+ hentry = h->descriptor;
+ BFD_ASSERT (hentry != NULL
+ && (hentry->root.type == bfd_link_hash_defined
+ || hentry->root.type == bfd_link_hash_defweak));
+ esec = hentry->root.u.def.section;
+ bfd_put_32 (output_bfd,
+ (esec->output_section->vma
+ + esec->output_offset
+ + hentry->root.u.def.value),
+ p);
+
+ irel = finfo->section_info[oindx].relocs + osec->reloc_count;
+ irel->r_vaddr = (osec->vma
+ + sec->output_offset
+ + h->root.u.def.value);
+ irel->r_symndx = esec->output_section->target_index;
+ irel->r_type = R_POS;
+ irel->r_size = 31;
+ finfo->section_info[oindx].rel_hashes[osec->reloc_count] = NULL;
+ ++osec->reloc_count;
+
+ ldrel.l_vaddr = irel->r_vaddr;
+ if (strcmp (esec->output_section->name, ".text") == 0)
+ ldrel.l_symndx = 0;
+ else if (strcmp (esec->output_section->name, ".data") == 0)
+ ldrel.l_symndx = 1;
+ else if (strcmp (esec->output_section->name, ".bss") == 0)
+ ldrel.l_symndx = 2;
+ else
+ {
+ (*_bfd_error_handler)
+ ("%s: loader reloc in unrecognized section `%s'",
+ bfd_get_filename (output_bfd),
+ esec->output_section->name);
+ bfd_set_error (bfd_error_nonrepresentable_section);
+ return false;
+ }
+ ldrel.l_rtype = (31 << 8) | R_POS;
+ ldrel.l_rsecnm = oindx;
+ xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel);
+ ++finfo->ldrel;
+
+ bfd_put_32 (output_bfd, xcoff_data (output_bfd)->toc, p + 4);
+
+ tsec = xcoff_data (output_bfd)->toc_section;
+
+ ++irel;
+ irel->r_vaddr = (osec->vma
+ + sec->output_offset
+ + h->root.u.def.value
+ + 4);
+ irel->r_symndx = tsec->output_section->target_index;
+ irel->r_type = R_POS;
+ irel->r_size = 31;
+ finfo->section_info[oindx].rel_hashes[osec->reloc_count] = NULL;
+ ++osec->reloc_count;
+
+ ldrel.l_vaddr = irel->r_vaddr;
+ if (strcmp (tsec->output_section->name, ".text") == 0)
+ ldrel.l_symndx = 0;
+ else if (strcmp (tsec->output_section->name, ".data") == 0)
+ ldrel.l_symndx = 1;
+ else if (strcmp (tsec->output_section->name, ".bss") == 0)
+ ldrel.l_symndx = 2;
+ else
+ {
+ (*_bfd_error_handler)
+ ("%s: loader reloc in unrecognized section `%s'",
+ bfd_get_filename (output_bfd),
+ tsec->output_section->name);
+ bfd_set_error (bfd_error_nonrepresentable_section);
+ return false;
+ }
+ ldrel.l_rtype = (31 << 8) | R_POS;
+ ldrel.l_rsecnm = oindx;
+ xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel);
+ ++finfo->ldrel;
+ }
+
if (h->indx >= 0)
return true;