#include <sys/file.h>
#include <assert.h>
#include <getopt.h>
-#include <bfd.h>
-#include <libiberty.h>
+#include "bfd.h"
+#include "libiberty.h"
#include "sysdep.h"
#include "bucomm.h"
/* Internal BFD NLM header. */
#include "libnlm.h"
#include "nlmconv.h"
-/* Needed for Alpha support. */
+#ifdef NLMCONV_ALPHA
#include "coff/sym.h"
#include "coff/ecoff.h"
+#endif
/* If strerror is just a macro, we want to use the one from libiberty
since it will handle undefined values. */
/* The symbol table. */
static asymbol **symbols;
+/* A section we create in the output file to hold pointers to where
+ the sections of the input file end up. We will put a pointer to
+ this section in the NLM header. These is an entry for each input
+ section. The format is
+ null terminated section name
+ zeroes to adjust to 4 byte boundary
+ 4 byte section data file pointer
+ 4 byte section size
+ We don't need a version number. The way we find this information
+ is by finding a stamp in the NLM header information. If we need to
+ change the format of this information, we can simply change the
+ stamp. */
+static asection *secsec;
+
/* A temporary file name to be unlinked on exit. Actually, for most
errors, we leave it around. It's not clear whether that is helpful
or not. */
static void setup_sections PARAMS ((bfd *, asection *, PTR));
static void copy_sections PARAMS ((bfd *, asection *, PTR));
static void mangle_relocs PARAMS ((bfd *, asection *, arelent ***,
- bfd_size_type *, char *,
+ long *, char *,
bfd_size_type));
-static void i386_mangle_relocs PARAMS ((bfd *, asection *, arelent ***,
- bfd_size_type *, char *,
- bfd_size_type));
-static void alpha_mangle_relocs PARAMS ((bfd *, asection *, arelent ***,
- bfd_size_type *, char *,
- bfd_size_type));
-/* start-sanitize-powerpc-netware */
-static void powerpc_build_stubs PARAMS ((bfd *, asymbol ***, unsigned int *));
-static void powerpc_resolve_stubs PARAMS ((bfd *, bfd *));
-static void powerpc_mangle_relocs PARAMS ((bfd *, asection *, arelent ***,
- bfd_size_type *, char *,
- bfd_size_type));
-/* end-sanitize-powerpc-netware */
static void default_mangle_relocs PARAMS ((bfd *, asection *, arelent ***,
- bfd_size_type *, char *,
+ long *, char *,
bfd_size_type));
static char *link_inputs PARAMS ((struct string_list *, char *));
static const char *choose_temp_base_try PARAMS ((const char *,
const char *));
static void choose_temp_base PARAMS ((void));
static int pexecute PARAMS ((char *, char *[]));
+
+#ifdef NLMCONV_I386
+static void i386_mangle_relocs PARAMS ((bfd *, asection *, arelent ***,
+ long *, char *,
+ bfd_size_type));
+#endif
+
+#ifdef NLMCONV_ALPHA
+static void alpha_mangle_relocs PARAMS ((bfd *, asection *, arelent ***,
+ long *, char *,
+ bfd_size_type));
+#endif
+
+#ifdef NLMCONV_POWERPC
+static void powerpc_build_stubs PARAMS ((bfd *, bfd *, asymbol ***, long *));
+static void powerpc_resolve_stubs PARAMS ((bfd *, bfd *));
+static void powerpc_mangle_relocs PARAMS ((bfd *, asection *, arelent ***,
+ long *, char *,
+ bfd_size_type));
+#endif
\f
/* The main routine. */
bfd *inbfd;
bfd *outbfd;
asymbol **newsyms, **outsyms;
- unsigned int symcount, newsymalloc, newsymcount;
+ long symcount, newsymalloc, newsymcount;
+ long symsize;
asection *text_sec, *bss_sec, *data_sec;
bfd_vma vma;
bfd_size_type align;
asymbol *endsym;
- unsigned int i;
+ long i;
char inlead, outlead;
boolean gotstart, gotexit, gotcheck;
struct stat st;
if (! bfd_set_file_flags (outbfd, bfd_get_file_flags (inbfd)))
bfd_fatal (bfd_get_filename (outbfd));
- symbols = (asymbol **) xmalloc (get_symtab_upper_bound (inbfd));
+ symsize = bfd_get_symtab_upper_bound (inbfd);
+ if (symsize < 0)
+ bfd_fatal (input_file);
+ symbols = (asymbol **) xmalloc (symsize);
symcount = bfd_canonicalize_symtab (inbfd, symbols);
+ if (symcount < 0)
+ bfd_fatal (input_file);
/* Make sure we have a .bss section. */
bss_sec = bfd_get_section_by_name (outbfd, NLM_UNINITIALIZED_DATA_NAME);
|| ! bfd_set_section_alignment (outbfd, bss_sec, 1))
bfd_fatal ("make .bss section");
}
-/* start-sanitize-powerpc-netware */
+ /* We store the original section names in the .nlmsections section,
+ so that programs which understand it can resurrect the original
+ sections from the NLM. We will put a pointer to .nlmsections in
+ the NLM header area. */
+ secsec = bfd_make_section (outbfd, ".nlmsections");
+ if (secsec == NULL)
+ bfd_fatal ("make .nlmsections section");
+ if (! bfd_set_section_flags (outbfd, secsec, SEC_HAS_CONTENTS))
+ bfd_fatal ("set .nlmsections flags");
+
+#ifdef NLMCONV_POWERPC
/* For PowerPC NetWare we need to build stubs for calls to undefined
symbols. Because each stub requires an entry in the TOC section
which must be at the same location as other entries in the TOC
section, we must do this before determining where the TOC section
goes in setup_sections. */
- powerpc_build_stubs (inbfd, &symbols, &symcount);
-/* end-sanitize-powerpc-netware */
+ if (bfd_get_arch (inbfd) == bfd_arch_powerpc)
+ powerpc_build_stubs (inbfd, outbfd, &symbols, &symcount);
+#endif
/* Set up the sections. */
bfd_map_over_sections (inbfd, setup_sections, (PTR) outbfd);
symbols will confuse it. */
if ((sym->flags & BSF_DEBUGGING) == 0
&& bfd_asymbol_name (sym)[0] == '_'
- && bfd_get_section (sym) == &bfd_und_section)
+ && bfd_is_und_section (bfd_get_section (sym)))
{
if (strcmp (bfd_asymbol_name (sym), "_edata") == 0)
{
sym->section = bss_sec;
endsym = sym;
}
-/* start-sanitize-powerpc-netware */
+
+#ifdef NLMCONV_POWERPC
/* For PowerPC NetWare, we define __GOT0. This is the start
of the .got section. */
if (bfd_get_arch (inbfd) == bfd_arch_powerpc
sym->value = got_sec->output_offset;
sym->section = got_sec->output_section;
}
-/* end-sanitize-powerpc-netware */
+#endif
}
/* If this is a global symbol, check the export list. */
/* If it's an undefined symbol, see if it's on the import list.
Change the prefix if necessary. */
- if (bfd_get_section (sym) == &bfd_und_section)
+ if (bfd_is_und_section (bfd_get_section (sym)))
{
register struct string_list *l;
is what NLMLINK does. */
strncpy (nlm_extended_header (outbfd)->stamp, "MeSsAgEs", 8);
+ strncpy (nlm_cygnus_ext_header (outbfd)->stamp, "CyGnUsEx", 8);
+
/* If the date was not given, force it in. */
if (nlm_version_header (outbfd)->month == 0
&& nlm_version_header (outbfd)->day == 0
nlm_version_header (outbfd)->year = ptm->tm_year + 1900;
strncpy (version_hdr->stamp, "VeRsIoN#", 8);
}
-/* start-sanitize-powerpc-netware */
+#ifdef NLMCONV_POWERPC
/* Resolve the stubs we build for PowerPC NetWare. */
- powerpc_resolve_stubs (inbfd, outbfd);
-/* end-sanitize-powerpc-netware */
+ if (bfd_get_arch (inbfd) == bfd_arch_powerpc)
+ powerpc_resolve_stubs (inbfd, outbfd);
+#endif
/* Copy over the sections. */
bfd_map_over_sections (inbfd, copy_sections, (PTR) outbfd);
strncpy (nlm_variable_header (outbfd)->oldThreadName, " LONG",
NLM_OLD_THREAD_NAME_LENGTH);
+ nlm_cygnus_ext_header (outbfd)->offset = secsec->filepos;
+ nlm_cygnus_ext_header (outbfd)->length = bfd_section_size (outbfd, secsec);
+
if (! bfd_close (outbfd))
bfd_fatal (output_file);
if (! bfd_close (inbfd))
{
switch (arch)
{
+#ifdef NLMCONV_I386
case bfd_arch_i386:
return "nlm32-i386";
+#endif
+#ifdef NLMCONV_SPARC
case bfd_arch_sparc:
return "nlm32-sparc";
+#endif
+#ifdef NLMCONV_ALPHA
case bfd_arch_alpha:
return "nlm32-alpha";
-/* start-sanitize-powerpc-netware */
+#endif
+#ifdef NLMCONV_POWERPC
case bfd_arch_powerpc:
return "nlm32-powerpc";
-/* end-sanitize-powerpc-netware */
+#endif
default:
- fprintf (stderr, "%s: no default NLM format for %s\n",
+ fprintf (stderr, "%s: support not compiled in for %s\n",
program_name, bfd_printable_arch_mach (arch, mach));
exit (1);
/* Avoid warning. */
bfd_vma offset;
bfd_size_type align;
bfd_size_type add;
-
- /* FIXME: We don't want to copy the .reginfo section of an ECOFF
- file. However, I don't have a good way to describe this section.
- We do want to copy the section when using objcopy. */
- if (bfd_get_flavour (inbfd) == bfd_target_ecoff_flavour
- && strcmp (bfd_section_name (inbfd, insec), ".reginfo") == 0)
- return;
+ bfd_size_type secsecsize;
f = bfd_get_section_flags (inbfd, insec);
if (f & SEC_CODE)
bfd_fatal ("set section flags");
bfd_set_reloc (outbfd, outsec, (arelent **) NULL, 0);
+
+ /* For each input section we allocate space for an entry in
+ .nlmsections. */
+ secsecsize = bfd_section_size (outbfd, secsec);
+ secsecsize += strlen (bfd_section_name (inbfd, insec)) + 1;
+ secsecsize = (secsecsize + 3) &~ 3;
+ secsecsize += 8;
+ if (! bfd_set_section_size (outbfd, secsec, secsecsize))
+ bfd_fatal ("set .nlmsections size");
}
/* Copy the section contents. */
asection *insec;
PTR data_ptr;
{
+ static bfd_size_type secsecoff = 0;
bfd *outbfd = (bfd *) data_ptr;
+ const char *inname;
asection *outsec;
bfd_size_type size;
PTR contents;
- bfd_size_type reloc_size;
+ long reloc_size;
+ bfd_byte buf[4];
+ bfd_size_type add;
- /* FIXME: We don't want to copy the .reginfo section of an ECOFF
- file. However, I don't have a good way to describe this section.
- We do want to copy the section when using objcopy. */
- if (bfd_get_flavour (inbfd) == bfd_target_ecoff_flavour
- && strcmp (bfd_section_name (inbfd, insec), ".reginfo") == 0)
- return;
+ inname = bfd_section_name (inbfd, insec);
outsec = insec->output_section;
assert (outsec != NULL);
size = bfd_get_section_size_before_reloc (insec);
- if (size == 0)
- return;
/* FIXME: Why are these necessary? */
insec->_cooked_size = insec->_raw_size;
}
reloc_size = bfd_get_reloc_upper_bound (inbfd, insec);
+ if (reloc_size < 0)
+ bfd_fatal (bfd_get_filename (inbfd));
if (reloc_size != 0)
{
arelent **relocs;
- bfd_size_type reloc_count;
+ long reloc_count;
relocs = (arelent **) xmalloc (reloc_size);
reloc_count = bfd_canonicalize_reloc (inbfd, insec, relocs, symbols);
+ if (reloc_count < 0)
+ bfd_fatal (bfd_get_filename (inbfd));
mangle_relocs (outbfd, insec, &relocs, &reloc_count, (char *) contents,
size);
arelent **combined;
total_count = reloc_count + outsec->reloc_count;
- combined = (arelent **) xmalloc (total_count * sizeof (arelent));
+ combined = (arelent **) xmalloc (total_count * sizeof (arelent *));
memcpy (combined, outsec->orelocation,
- outsec->reloc_count * sizeof (arelent));
+ outsec->reloc_count * sizeof (arelent *));
memcpy (combined + outsec->reloc_count, relocs,
- (size_t) (reloc_count * sizeof (arelent)));
+ (size_t) (reloc_count * sizeof (arelent *)));
free (outsec->orelocation);
reloc_count = total_count;
relocs = combined;
bfd_fatal (bfd_get_filename (outbfd));
free (contents);
}
+
+ /* Add this section to .nlmsections. */
+ if (! bfd_set_section_contents (outbfd, secsec, (PTR) inname, secsecoff,
+ strlen (inname) + 1))
+ bfd_fatal ("set .nlmsection contents");
+ secsecoff += strlen (inname) + 1;
+
+ add = ((secsecoff + 3) &~ 3) - secsecoff;
+ if (add != 0)
+ {
+ bfd_h_put_32 (outbfd, (bfd_vma) 0, buf);
+ if (! bfd_set_section_contents (outbfd, secsec, buf, secsecoff, add))
+ bfd_fatal ("set .nlmsection contents");
+ secsecoff += add;
+ }
+
+ if (contents != NULL)
+ bfd_h_put_32 (outbfd, (bfd_vma) outsec->filepos, buf);
+ else
+ bfd_h_put_32 (outbfd, (bfd_vma) 0, buf);
+ if (! bfd_set_section_contents (outbfd, secsec, buf, secsecoff, 4))
+ bfd_fatal ("set .nlmsection contents");
+ secsecoff += 4;
+
+ bfd_h_put_32 (outbfd, (bfd_vma) size, buf);
+ if (! bfd_set_section_contents (outbfd, secsec, buf, secsecoff, 4))
+ bfd_fatal ("set .nlmsection contents");
+ secsecoff += 4;
}
/* Some, perhaps all, NetWare targets require changing the relocs used
bfd *outbfd;
asection *insec;
arelent ***relocs_ptr;
- bfd_size_type *reloc_count_ptr;
+ long *reloc_count_ptr;
char *contents;
bfd_size_type contents_size;
{
switch (bfd_get_arch (outbfd))
{
+#ifdef NLMCONV_I386
case bfd_arch_i386:
i386_mangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr,
contents, contents_size);
break;
+#endif
+#ifdef NLMCONV_ALPHA
case bfd_arch_alpha:
alpha_mangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr,
contents, contents_size);
break;
-/* start-sanitize-powerpc-netware */
+#endif
+#ifdef NLMCONV_POWERPC
case bfd_arch_powerpc:
powerpc_mangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr,
contents, contents_size);
break;
-/* end-sanitize-powerpc-netware */
+#endif
default:
default_mangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr,
contents, contents_size);
bfd *outbfd;
asection *insec;
arelent ***relocs_ptr;
- bfd_size_type *reloc_count_ptr;
+ long *reloc_count_ptr;
char *contents;
bfd_size_type contents_size;
{
if (insec->output_offset != 0)
{
- bfd_size_type reloc_count;
+ long reloc_count;
register arelent **relocs;
- register bfd_size_type i;
+ register long i;
reloc_count = *reloc_count_ptr;
relocs = *relocs_ptr;
(*relocs)->address += insec->output_offset;
}
}
+\f
+#ifdef NLMCONV_I386
/* NetWare on the i386 supports a restricted set of relocs, which are
different from those used on other i386 targets. This routine
bfd *outbfd;
asection *insec;
arelent ***relocs_ptr;
- bfd_size_type *reloc_count_ptr;
+ long *reloc_count_ptr;
char *contents;
bfd_size_type contents_size;
{
- bfd_size_type reloc_count, i;
+ long reloc_count, i;
arelent **relocs;
reloc_count = *reloc_count_ptr;
/* Adjust the reloc for the changes we just made. */
rel->addend = 0;
- if (bfd_get_section (sym) != &bfd_und_section)
+ if (! bfd_is_und_section (bfd_get_section (sym)))
rel->sym_ptr_ptr = bfd_get_section (sym)->symbol_ptr_ptr;
}
}
}
+#endif /* NLMCONV_I386 */
+\f
+#ifdef NLMCONV_ALPHA
+
/* On the Alpha the first reloc for every section must be a special
relocs which hold the GP address. Also, the first reloc in the
file must be a special reloc which holds the address of the .lita
bfd *outbfd;
asection *insec;
register arelent ***relocs_ptr;
- bfd_size_type *reloc_count_ptr;
+ long *reloc_count_ptr;
char *contents;
bfd_size_type contents_size;
{
- bfd_size_type old_reloc_count;
+ long old_reloc_count;
arelent **old_relocs;
register arelent **relocs;
}
*relocs = (arelent *) xmalloc (sizeof (arelent));
- (*relocs)->sym_ptr_ptr = bfd_abs_section.symbol_ptr_ptr;
+ (*relocs)->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
(*relocs)->address = nlm_alpha_backend_data (outbfd)->lita_address;
(*relocs)->addend = nlm_alpha_backend_data (outbfd)->lita_size + 1;
(*relocs)->howto = &nlm32_alpha_nw_howto;
++(*reloc_count_ptr);
}
- /* Get the GP value from bfd. It is in the .reginfo section. */
+ /* Get the GP value from bfd. */
if (nlm_alpha_backend_data (outbfd)->gp == 0)
- {
- bfd *inbfd;
- asection *reginfo_sec;
- struct ecoff_reginfo sreginfo;
-
- inbfd = insec->owner;
- assert (bfd_get_flavour (inbfd) == bfd_target_ecoff_flavour);
- reginfo_sec = bfd_get_section_by_name (inbfd, REGINFO);
- if (reginfo_sec != (asection *) NULL
- && bfd_get_section_contents (inbfd, reginfo_sec,
- (PTR) &sreginfo, (file_ptr) 0,
- sizeof sreginfo) != false)
- nlm_alpha_backend_data (outbfd)->gp = sreginfo.gp_value;
- }
+ nlm_alpha_backend_data (outbfd)->gp =
+ bfd_ecoff_get_gp_value (insec->owner);
*relocs = (arelent *) xmalloc (sizeof (arelent));
- (*relocs)->sym_ptr_ptr = bfd_abs_section.symbol_ptr_ptr;
+ (*relocs)->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
(*relocs)->address = nlm_alpha_backend_data (outbfd)->gp;
(*relocs)->addend = 0;
(*relocs)->howto = &nlm32_alpha_nw_howto;
(*relocs)->address += insec->output_offset;
}
}
-/* start-sanitize-powerpc-netware */
+
+#endif /* NLMCONV_ALPHA */
+\f
+#ifdef NLMCONV_POWERPC
/* We keep a linked list of stubs which we must build. Because BFD
requires us to know the sizes of all sections before we can set the
build a stub for each one. */
static void
-powerpc_build_stubs (inbfd, symbols_ptr, symcount_ptr)
+powerpc_build_stubs (inbfd, outbfd, symbols_ptr, symcount_ptr)
bfd *inbfd;
+ bfd *outbfd;
asymbol ***symbols_ptr;
- unsigned int *symcount_ptr;
+ long *symcount_ptr;
{
asection *stub_sec;
asection *got_sec;
unsigned int got_base;
- unsigned int i;
- unsigned int symcount;
- unsigned int stubcount;
+ long i;
+ long symcount;
+ long stubcount;
/* Make a section to hold stubs. We don't set SEC_HAS_CONTENTS for
the section to prevent copy_sections from reading from it. */
/* We must make a stub for every undefined symbol whose name
starts with '.'. */
if (bfd_asymbol_name (sym)[0] != '.'
- || bfd_get_section (sym) != &bfd_und_section)
+ || ! bfd_is_und_section (bfd_get_section (sym)))
continue;
/* Make a new undefined symbol with the same name but without
/* Define the `.' symbol to be in the stub section. */
sym->section = stub_sec;
sym->value = stubcount * POWERPC_STUB_SIZE;
- sym->flags = BSF_LOCAL;
+ /* We set the BSF_DYNAMIC flag here so that we can check it when
+ we are mangling relocs. FIXME: This is a hack. */
+ sym->flags = BSF_LOCAL | BSF_DYNAMIC;
/* Add this stub to the linked list. */
item = (struct powerpc_stub *) xmalloc (sizeof (struct powerpc_stub));
* POWERPC_STUB_TOC_ENTRY_SIZE))))
bfd_fatal ("stub section sizes");
}
+
+ /* PowerPC NetWare requires a custom header. We create it here.
+ The first word is the header version number, currently 1. The
+ second word is the timestamp of the input file. Unfortunately,
+ they do not conform to the emergent standard for custom headers.
+ We must fake the version number and timestamp in the offset and
+ length fields. */
+ memcpy (nlm_custom_header (outbfd)->stamp, "CuStHeAd", 8);
+ nlm_custom_header (outbfd)->hdrLength = 0;
+ /* Put version number in dataOffset field. */
+ nlm_custom_header (outbfd)->dataOffset = 1;
+ /* Put timestamp in length field. */
+ {
+ struct stat s;
+
+ if (stat (bfd_get_filename (inbfd), &s) < 0)
+ s.st_mtime = 0;
+ nlm_custom_header (outbfd)->dataLength = s.st_mtime;
+ }
+ /* No data stamp. */
+ memset (nlm_custom_header (outbfd)->dataStamp, 0,
+ sizeof (nlm_custom_header (outbfd)->dataStamp));
}
/* Resolve all the stubs for PowerPC NetWare. We fill in the contents
bfd *outbfd;
asection *insec;
register arelent ***relocs_ptr;
- bfd_size_type *reloc_count_ptr;
+ long *reloc_count_ptr;
char *contents;
bfd_size_type contents_size;
{
const reloc_howto_type *toc_howto;
- bfd_size_type reloc_count;
+ long reloc_count;
register arelent **relocs;
- register bfd_size_type i;
+ register long i;
toc_howto = bfd_reloc_type_lookup (insec->owner, BFD_RELOC_PPC_TOC16);
if (toc_howto == (reloc_howto_type *) NULL)
& rel->howto->dst_mask));
bfd_put_32 (outbfd, val, (bfd_byte *) contents + rel->address);
- /* If this reloc is against a symbol whose name begins
- with a `.', and the next instruction is
+ /* If this reloc is against an stubbed symbol and the
+ next instruction is
cror 31,31,31
then we replace the next instruction with
lwz r2,20(r1)
- This reloads the TOC pointer after a call. */
+ This reloads the TOC pointer after a stub call. */
if (bfd_asymbol_name (sym)[0] == '.'
+ && (sym->flags & BSF_DYNAMIC) != 0
&& (bfd_get_32 (outbfd,
(bfd_byte *) contents + rel->address + 4)
== 0x4ffffb82)) /* cror 31,31,31 */
rel->address += insec->output_offset;
}
}
-/* end-sanitize-powerpc-netware */
+
+#endif /* NLMCONV_POWERPC */
\f
/* Name of linker. */
#ifndef LD_NAME