#define STRING_SIZE_SIZE (4)
+/* We use a hash table to merge identical enum, struct, and union
+ definitions in the linker. */
+
+/* Information we keep for a single element (an enum value, a
+ structure or union field) in the debug merge hash table. */
+
+struct coff_debug_merge_element
+{
+ /* Next element. */
+ struct coff_debug_merge_element *next;
+
+ /* Name. */
+ const char *name;
+
+ /* Type. */
+ unsigned int type;
+
+ /* Symbol index for complex type. */
+ long tagndx;
+};
+
+/* A linked list of debug merge entries for a given name. */
+
+struct coff_debug_merge_type
+{
+ /* Next type with the same name. */
+ struct coff_debug_merge_type *next;
+
+ /* Class of type. */
+ int class;
+
+ /* Symbol index where this type is defined. */
+ long indx;
+
+ /* List of elements. */
+ struct coff_debug_merge_element *elements;
+};
+
+/* Information we store in the debug merge hash table. */
+
+struct coff_debug_merge_hash_entry
+{
+ struct bfd_hash_entry root;
+
+ /* A list of types with this name. */
+ struct coff_debug_merge_type *types;
+};
+
+/* The debug merge hash table. */
+
+struct coff_debug_merge_hash_table
+{
+ struct bfd_hash_table root;
+};
+
+/* Initialize a COFF debug merge hash table. */
+
+#define coff_debug_merge_hash_table_init(table) \
+ (bfd_hash_table_init (&(table)->root, coff_debug_merge_hash_newfunc))
+
+/* Free a COFF debug merge hash table. */
+
+#define coff_debug_merge_hash_table_free(table) \
+ (bfd_hash_table_free (&(table)->root))
+
+/* Look up an entry in a COFF debug merge hash table. */
+
+#define coff_debug_merge_hash_lookup(table, string, create, copy) \
+ ((struct coff_debug_merge_hash_entry *) \
+ bfd_hash_lookup (&(table)->root, (string), (create), (copy)))
+
/* Information we keep for each section in the output file when doing
a relocateable link. */
bfd *output_bfd;
/* Used to indicate failure in traversal routine. */
boolean failed;
- /* Hash table for long symbol name. */
+ /* Hash table for long symbol names. */
struct bfd_strtab_hash *strtab;
/* When doing a relocateable link, an array of information kept for
each output section, indexed by the target_index field. */
long last_file_index;
/* Contents of last C_FILE symbol. */
struct internal_syment last_file;
+ /* Hash table used to merge debug information. */
+ struct coff_debug_merge_hash_table debug_merge;
/* Buffer large enough to hold swapped symbols of any input file. */
struct internal_syment *internal_syms;
/* Buffer large enough to hold sections of symbols of any input file. */
bfd_byte *external_relocs;
/* Buffer large enough to hold swapped relocs of any input section. */
struct internal_reloc *internal_relocs;
-
-enum bfd_link_subsystem subsystem;
-bfd_link_stack_heap stack_heap_parameters;
};
-static struct bfd_hash_entry *coff_link_hash_newfunc
+static struct bfd_hash_entry *coff_debug_merge_hash_newfunc
PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
static boolean coff_link_add_object_symbols
PARAMS ((bfd *, struct bfd_link_info *));
static boolean coff_link_check_archive_element
PARAMS ((bfd *, struct bfd_link_info *, boolean *));
-static boolean coff_link_get_symbols PARAMS ((bfd *));
-static const char *coff_read_string_table PARAMS ((bfd *));
-static boolean coff_link_free_symbols PARAMS ((bfd *));
static boolean coff_link_check_ar_symbols
PARAMS ((bfd *, struct bfd_link_info *, boolean *));
static boolean coff_link_add_symbols PARAMS ((bfd *, struct bfd_link_info *));
PARAMS ((bfd *, struct coff_final_link_info *, asection *,
struct bfd_link_order *));
-
-/* These new data and data types are used to keep track of the .idata$4 and
- .idata$5 relocations which are put into the .idata section for all of the
- *.dll input libraries linked in. This is not a great solution, and may
- break in the future if MS changes the format of its libraries, but it
- does work for the collection of mstools libraries we are currently working
- with. The main problem is that there are some new majic symbols defined
- in the libraries which are non-standard coff and simply aren't handled
- completely by ld. What has been included here will help finish up the job.
- Basically, during the link, .idata$4 and .idata$5 pointers are correctly
- relocated to the image. At the very end of the link, the .idata$2
- information is written. This data appears at the beginning of the .idata
- section and a 'set' of information appears for each *.dll passed in.
- Each set of information consists of 3 addresses, a pointer to the .idata$4
- start, a pointer to .idata$6 (which has the name of the dll), and a pointer
- to .idata$5 start. The idata$4 and 5 information is a list of pointers
- which appear to point to the name of various functions found within the dll.
- When invoked, the loader will write over these names with the correct
- addresses to use for these functions.
- Without this 'fix', all information appears correctly except for the
- addresses of the .idata$4 and 5 starts within the .idata$2 portion of the
- .idata section. What we will do is to keep track of the dll's processed
- and the number of functions needed from each dll. From this information
- we can correctly compute the start of the idata$4 and 5 lists for each
- dll in the idata section */
-static int num_DLLs_done = 0;
-static int num_DLLs = 0;
-static int all_entries = 0;
-struct DLL_struct {
- const char * DLL_name;
- int num_entries;
-};
-struct DLL_struct MS_DLL[10];
-static bfd_vma idata_4_prev = 0;
-static bfd_vma idata_5_prev = 0;
-static bfd_vma add_to_val = 0;
-
-
-
/* Create an entry in a COFF linker hash table. */
-static struct bfd_hash_entry *
-coff_link_hash_newfunc (entry, table, string)
+struct bfd_hash_entry *
+_bfd_coff_link_hash_newfunc (entry, table, string)
struct bfd_hash_entry *entry;
struct bfd_hash_table *table;
const char *string;
ret->numaux = 0;
ret->auxbfd = NULL;
ret->aux = NULL;
+ ret->toc_offset = 1; /* invalid toc address, sets the high bit */
}
return (struct bfd_hash_entry *) ret;
}
+/* Initialize a COFF linker hash table. */
+
+boolean
+_bfd_coff_link_hash_table_init (table, abfd, newfunc)
+ struct coff_link_hash_table *table;
+ bfd *abfd;
+ struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *,
+ struct bfd_hash_table *,
+ const char *));
+{
+ return _bfd_link_hash_table_init (&table->root, abfd, newfunc);
+}
+
/* Create a COFF linker hash table. */
struct bfd_link_hash_table *
struct coff_link_hash_table *ret;
ret = ((struct coff_link_hash_table *)
- malloc (sizeof (struct coff_link_hash_table)));
+ bfd_alloc (abfd, sizeof (struct coff_link_hash_table)));
if (ret == NULL)
{
bfd_set_error (bfd_error_no_memory);
return NULL;
}
- if (! _bfd_link_hash_table_init (&ret->root, abfd,
- coff_link_hash_newfunc))
+ if (! _bfd_coff_link_hash_table_init (ret, abfd,
+ _bfd_coff_link_hash_newfunc))
{
- free (ret);
+ bfd_release (abfd, ret);
return (struct bfd_link_hash_table *) NULL;
}
return &ret->root;
}
+/* Create an entry in a COFF debug merge hash table. */
+
+static struct bfd_hash_entry *
+coff_debug_merge_hash_newfunc (entry, table, string)
+ struct bfd_hash_entry *entry;
+ struct bfd_hash_table *table;
+ const char *string;
+{
+ struct coff_debug_merge_hash_entry *ret =
+ (struct coff_debug_merge_hash_entry *) entry;
+
+ /* Allocate the structure if it has not already been allocated by a
+ subclass. */
+ if (ret == (struct coff_debug_merge_hash_entry *) NULL)
+ ret = ((struct coff_debug_merge_hash_entry *)
+ bfd_hash_allocate (table,
+ sizeof (struct coff_debug_merge_hash_entry)));
+ if (ret == (struct coff_debug_merge_hash_entry *) NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return (struct bfd_hash_entry *) ret;
+ }
+
+ /* Call the allocation method of the superclass. */
+ ret = ((struct coff_debug_merge_hash_entry *)
+ bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
+ if (ret != (struct coff_debug_merge_hash_entry *) NULL)
+ {
+ /* Set local fields. */
+ ret->types = NULL;
+ }
+
+ return (struct bfd_hash_entry *) ret;
+}
+
/* Given a COFF BFD, add symbols to the global hash table as
appropriate. */
bfd *abfd;
struct bfd_link_info *info;
{
- if (! coff_link_get_symbols (abfd))
+ if (! _bfd_coff_get_external_symbols (abfd))
return false;
if (! coff_link_add_symbols (abfd, info))
return false;
+
if (! info->keep_memory)
{
- if (! coff_link_free_symbols (abfd))
+ if (! _bfd_coff_free_symbols (abfd))
return false;
}
return true;
struct bfd_link_info *info;
boolean *pneeded;
{
- if (! coff_link_get_symbols (abfd))
+ if (! _bfd_coff_get_external_symbols (abfd))
return false;
if (! coff_link_check_ar_symbols (abfd, info, pneeded))
if (! info->keep_memory || ! *pneeded)
{
- if (! coff_link_free_symbols (abfd))
+ if (! _bfd_coff_free_symbols (abfd))
return false;
}
return true;
}
-/* Read in the external symbols. */
-
-static boolean
-coff_link_get_symbols (abfd)
- bfd *abfd;
-{
- bfd_size_type symesz;
- size_t size;
- PTR syms;
-
- if (obj_coff_external_syms (abfd) != NULL)
- return true;
-
- symesz = bfd_coff_symesz (abfd);
-
- size = obj_raw_syment_count (abfd) * symesz;
-
- syms = malloc (size);
- if (syms == NULL && size != 0)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
-
- if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0
- || bfd_read (syms, size, 1, abfd) != size)
- {
- if (syms != NULL)
- free (syms);
- return false;
- }
-
- obj_coff_external_syms (abfd) = syms;
-
- return true;
-}
-
-/* Read in the external strings. The strings are not loaded until
- they are needed. This is because we have no simple way of
- detecting a missing string table in an archive. */
-
-static const char *
-coff_read_string_table (abfd)
- bfd *abfd;
-{
- char extstrsize[STRING_SIZE_SIZE];
- size_t strsize;
- char *strings;
-
- if (obj_coff_strings (abfd) != NULL)
- return obj_coff_strings (abfd);
-
- if (bfd_seek (abfd,
- (obj_sym_filepos (abfd)
- + obj_raw_syment_count (abfd) * bfd_coff_symesz (abfd)),
- SEEK_SET) != 0)
- return NULL;
-
- if (bfd_read (extstrsize, sizeof extstrsize, 1, abfd) != sizeof extstrsize)
- {
- if (bfd_get_error () != bfd_error_file_truncated)
- return NULL;
-
- /* There is no string table. */
- strsize = STRING_SIZE_SIZE;
- }
- else
- {
-#if STRING_SIZE_SIZE == 4
- strsize = bfd_h_get_32 (abfd, (bfd_byte *) extstrsize);
-#else
- #error Change bfd_h_get_32
-#endif
- }
-
- strings = malloc (strsize);
- if (strings == NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- return NULL;
- }
-
- if (bfd_read (strings + STRING_SIZE_SIZE,
- strsize - STRING_SIZE_SIZE, 1, abfd)
- != strsize - STRING_SIZE_SIZE)
- {
- free (strings);
- return NULL;
- }
-
- obj_coff_strings (abfd) = strings;
-
- return strings;
-}
-
-/* Free up the external symbols and strings read from a COFF file. */
-
-static boolean
-coff_link_free_symbols (abfd)
- bfd *abfd;
-{
- if (obj_coff_external_syms (abfd) != NULL)
- {
- free (obj_coff_external_syms (abfd));
- obj_coff_external_syms (abfd) = NULL;
- }
- if (obj_coff_strings (abfd) != NULL)
- {
- free (obj_coff_strings (abfd));
- obj_coff_strings (abfd) = NULL;
- }
- return true;
-}
-
/* Look through the symbols to see if this object file should be
included in the link. */
boolean *pneeded;
{
boolean (*sym_is_global) PARAMS ((bfd *, struct internal_syment *));
- const char *strings;
bfd_size_type symesz;
bfd_byte *esym;
bfd_byte *esym_end;
*pneeded = false;
sym_is_global = coff_backend_info (abfd)->_bfd_coff_sym_is_global;
- strings = NULL;
symesz = bfd_coff_symesz (abfd);
esym = (bfd_byte *) obj_coff_external_syms (abfd);
/* This symbol is externally visible, and is defined by this
object file. */
- /* FIXME: It's not clear this will work correctly if sizeof
- (_n_zeroes) != 4. */
- if (sym._n._n_n._n_zeroes != 0
- || sym._n._n_n._n_offset == 0)
- {
- memcpy (buf, sym._n._n_name, SYMNMLEN);
- buf[SYMNMLEN] = '\0';
- name = buf;
- }
- else
- {
- BFD_ASSERT (sym._n._n_n._n_offset >= STRING_SIZE_SIZE);
- if (strings == NULL)
- {
- strings = coff_read_string_table (abfd);
- if (strings == NULL)
- return false;
- }
- name = strings + sym._n._n_n._n_offset;
- }
-
+ name = _bfd_coff_internal_syment_name (abfd, &sym, buf);
+ if (name == NULL)
+ return false;
h = bfd_link_hash_lookup (info->hash, name, false, false, true);
/* We are only interested in symbols that are currently
struct bfd_link_info *info;
{
boolean (*sym_is_global) PARAMS ((bfd *, struct internal_syment *));
- const char *strings;
boolean default_copy;
bfd_size_type symcount;
struct coff_link_hash_entry **sym_hash;
bfd_byte *esym_end;
sym_is_global = coff_backend_info (abfd)->_bfd_coff_sym_is_global;
- strings = NULL;
if (info->keep_memory)
default_copy = false;
/* This symbol is externally visible. */
- /* FIXME: It's not clear this will work correctly if sizeof
- (_n_zeroes) != 4. */
+ name = _bfd_coff_internal_syment_name (abfd, &sym, buf);
+ if (name == NULL)
+ return false;
+
+ /* We must copy the name into memory if we got it from the
+ syment itself, rather than the string table. */
copy = default_copy;
- if (sym._n._n_n._n_zeroes == 0
- && sym._n._n_n._n_offset != 0)
- {
- BFD_ASSERT (sym._n._n_n._n_offset >= STRING_SIZE_SIZE);
- if (strings == NULL)
- {
- strings = coff_read_string_table (abfd);
- if (strings == NULL)
- return false;
- }
- name = strings + sym._n._n_n._n_offset;
- }
- else
- {
- memcpy (buf, sym._n._n_name, SYMNMLEN);
- buf[SYMNMLEN] = '\0';
- name = buf;
- copy = true;
- }
+ if (sym._n._n_n._n_zeroes != 0
+ || sym._n._n_n._n_offset == 0)
+ copy = true;
value = sym.n_value;
(*sym_hash)->type = sym.n_type;
(*sym_hash)->numaux = sym.n_numaux;
(*sym_hash)->auxbfd = abfd;
+ (*sym_hash)->toc_offset = 1;
if (sym.n_numaux != 0)
{
union internal_auxent *alloc;
return true;
}
-
-/* parse out a -heap <reserved>,<commit> line */
-
-static char *
-dores_com (ptr, def,res, com)
- char *ptr;
- int *def;
- int *res;
- int *com;
-{
- *def = 1;
- *res = strtoul (ptr, &ptr, 0);
- if (ptr[0] == ',')
- *com = strtoul (ptr+1, &ptr, 0);
- return ptr;
-}
-
-static char *get_name(ptr, dst)
-char *ptr;
-char **dst;
-{
- while (*ptr == ' ')
- ptr++;
- *dst = ptr;
- while (*ptr && *ptr != ' ')
- ptr++;
- *ptr = 0;
- return ptr+1;
-}
-/* Process any magic embedded commands in a section called .drectve */
-
-static int
-process_embedded_commands (abfd)
- bfd *abfd;
-{
- asection *sec = bfd_get_section_by_name (abfd, ".drectve");
- char *s;
- char *e;
- char *copy;
- if (!sec)
- return 1;
-
- copy = malloc (sec->_raw_size);
- if (!copy)
- {
- bfd_set_error (bfd_error_no_memory);
- return 0;
- }
- if (! bfd_get_section_contents(abfd, sec, copy, 0, sec->_raw_size))
- {
- free (copy);
- return 0;
- }
- e = copy + sec->_raw_size;
- for (s = copy; s < e ; )
- {
- if (s[0]!= '-') {
- s++;
- continue;
- }
- if (strncmp (s,"-attr", 5) == 0)
- {
- char *name;
- char *attribs;
- asection *asec;
-
- int loop = 1;
- int had_write = 0;
- int had_read = 0;
- int had_exec= 0;
- int had_shared= 0;
- s += 5;
- s = get_name(s, &name);
- s = get_name(s, &attribs);
- while (loop) {
- switch (*attribs++)
- {
- case 'W':
- had_write = 1;
- break;
- case 'R':
- had_read = 1;
- break;
- case 'S':
- had_shared = 1;
- break;
- case 'X':
- had_exec = 1;
- break;
- default:
- loop = 0;
- }
- }
- asec = bfd_get_section_by_name (abfd, name);
- if (asec) {
- if (had_exec)
- asec->flags |= SEC_CODE;
- if (!had_write)
- asec->flags |= SEC_READONLY;
- }
- }
- else if (strncmp (s,"-heap", 5) == 0)
- {
- s = dores_com (s+5,
- &NT_stack_heap.heap_defined,
- &NT_stack_heap.heap_reserve,
- &NT_stack_heap.heap_commit);
- }
- else if (strncmp (s,"-stack", 6) == 0)
- {
- s = dores_com (s+6,
- &NT_stack_heap.heap_defined,
- &NT_stack_heap.heap_reserve,
- &NT_stack_heap.heap_commit);
- }
- else
- s++;
- }
- free (copy);
- return 1;
-}
+\f
/* Do the final link step. */
boolean
{
bfd_size_type symesz;
struct coff_final_link_info finfo;
+ boolean debug_merge_allocated;
asection *o;
struct bfd_link_order *p;
size_t max_contents_size;
finfo.contents = NULL;
finfo.external_relocs = NULL;
finfo.internal_relocs = NULL;
+ debug_merge_allocated = false;
- if (obj_pe(abfd))
- {
- /* store the subsystem, stack and heap parameters in variables defined
- in internal.h so that when they are needed to write the NT optional
- file header (coffcode.h), they will be available */
- NT_subsystem = info->subsystem;
- NT_stack_heap = info->stack_heap_parameters;
- }
+ coff_data (abfd)->link_info = info;
finfo.strtab = _bfd_stringtab_init ();
if (finfo.strtab == NULL)
goto error_return;
+ if (! coff_debug_merge_hash_table_init (&finfo.debug_merge))
+ goto error_return;
+ debug_merge_allocated = true;
+
/* Compute the file positions for all the sections. */
if (! abfd->output_has_begun)
bfd_coff_compute_section_file_positions (abfd);
* sizeof (struct internal_syment)));
finfo.sec_ptrs = (asection **) malloc (max_sym_count * sizeof (asection *));
finfo.sym_indices = (long *) malloc (max_sym_count * sizeof (long));
- finfo.outsyms = (bfd_byte *) malloc ((max_sym_count + 1) * symesz);
+ finfo.outsyms = ((bfd_byte *)
+ malloc ((size_t) ((max_sym_count + 1) * symesz)));
finfo.linenos = (bfd_byte *) malloc (max_lineno_count
* bfd_coff_linesz (abfd));
finfo.contents = (bfd_byte *) malloc (max_contents_size);
table in memory as we go along. We process all the relocations
for a single input file at once. */
obj_raw_syment_count (abfd) = 0;
+
+ if (coff_backend_info (abfd)->_bfd_coff_start_final_link)
+ {
+ if (! bfd_coff_start_final_link (abfd, info))
+ goto error_return;
+ }
+
for (o = abfd->sections; o != NULL; o = o->next)
{
for (p = o->link_order_head; p != NULL; p = p->next)
}
/* Free up the buffers used by coff_link_input_bfd. */
+
+ coff_debug_merge_hash_table_free (&finfo.debug_merge);
+ debug_merge_allocated = false;
+
if (finfo.internal_syms != NULL)
{
free (finfo.internal_syms);
index of the first external symbol. Write it out again if
necessary. */
if (finfo.last_file_index != -1
- && finfo.last_file.n_value != obj_raw_syment_count (abfd))
+ && (unsigned int) finfo.last_file.n_value != obj_raw_syment_count (abfd))
{
finfo.last_file.n_value = obj_raw_syment_count (abfd);
bfd_coff_swap_sym_out (abfd, (PTR) &finfo.last_file,
return true;
error_return:
+ if (debug_merge_allocated)
+ coff_debug_merge_hash_table_free (&finfo.debug_merge);
if (finfo.strtab != NULL)
_bfd_stringtab_free (finfo.strtab);
if (finfo.section_info != NULL)
return false;
}
+/* parse out a -heap <reserved>,<commit> line */
+
+static char *
+dores_com (ptr, output_bfd, heap)
+ char *ptr;
+ bfd *output_bfd;
+ int heap;
+{
+ if (coff_data(output_bfd)->pe)
+ {
+ int val = strtoul (ptr, &ptr, 0);
+ if (heap)
+ pe_data(output_bfd)->pe_opthdr.SizeOfHeapReserve =val;
+ else
+ pe_data(output_bfd)->pe_opthdr.SizeOfStackReserve =val;
+
+ if (ptr[0] == ',')
+ {
+ int val = strtoul (ptr+1, &ptr, 0);
+ if (heap)
+ pe_data(output_bfd)->pe_opthdr.SizeOfHeapCommit =val;
+ else
+ pe_data(output_bfd)->pe_opthdr.SizeOfStackCommit =val;
+ }
+ }
+ return ptr;
+}
+
+static char *get_name(ptr, dst)
+char *ptr;
+char **dst;
+{
+ while (*ptr == ' ')
+ ptr++;
+ *dst = ptr;
+ while (*ptr && *ptr != ' ')
+ ptr++;
+ *ptr = 0;
+ return ptr+1;
+}
+
+/* Process any magic embedded commands in a section called .drectve */
+
+static int
+process_embedded_commands (output_bfd, info, abfd)
+ bfd *output_bfd;
+ struct bfd_link_info *info;
+ bfd *abfd;
+{
+ asection *sec = bfd_get_section_by_name (abfd, ".drectve");
+ char *s;
+ char *e;
+ char *copy;
+ if (!sec)
+ return 1;
+
+ copy = malloc ((size_t) sec->_raw_size);
+ if (!copy)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return 0;
+ }
+ if (! bfd_get_section_contents(abfd, sec, copy, 0, sec->_raw_size))
+ {
+ free (copy);
+ return 0;
+ }
+ e = copy + sec->_raw_size;
+ for (s = copy; s < e ; )
+ {
+ if (s[0]!= '-') {
+ s++;
+ continue;
+ }
+ if (strncmp (s,"-attr", 5) == 0)
+ {
+ char *name;
+ char *attribs;
+ asection *asec;
+
+ int loop = 1;
+ int had_write = 0;
+ int had_read = 0;
+ int had_exec= 0;
+ int had_shared= 0;
+ s += 5;
+ s = get_name(s, &name);
+ s = get_name(s, &attribs);
+ while (loop) {
+ switch (*attribs++)
+ {
+ case 'W':
+ had_write = 1;
+ break;
+ case 'R':
+ had_read = 1;
+ break;
+ case 'S':
+ had_shared = 1;
+ break;
+ case 'X':
+ had_exec = 1;
+ break;
+ default:
+ loop = 0;
+ }
+ }
+ asec = bfd_get_section_by_name (abfd, name);
+ if (asec) {
+ if (had_exec)
+ asec->flags |= SEC_CODE;
+ if (!had_write)
+ asec->flags |= SEC_READONLY;
+ }
+ }
+ else if (strncmp (s,"-heap", 5) == 0)
+ {
+ s = dores_com (s+5, output_bfd, 1);
+ }
+ else if (strncmp (s,"-stack", 6) == 0)
+ {
+ s = dores_com (s+6, output_bfd, 0);
+ }
+ else
+ s++;
+ }
+ free (copy);
+ return 1;
+}
+
/* Link an input file into the linker output file. This function
handles all the sections and relocations of the input file at once. */
struct internal_syment *isymp;
asection **secpp;
long *indexp;
- long output_index;
+ unsigned long output_index;
bfd_byte *outsym;
struct coff_link_hash_entry **sym_hash;
- bfd_size_type relsz;
asection *o;
/* Move all the symbols to the output file. */
if ((output_bfd->flags & BFD_TRADITIONAL_FORMAT) != 0)
hash = false;
- if (! coff_link_get_symbols (input_bfd))
+ if (! _bfd_coff_get_external_symbols (input_bfd))
return false;
esym = (bfd_byte *) obj_coff_external_syms (input_bfd);
output_index = syment_base;
outsym = finfo->outsyms;
- if (obj_pe (output_bfd))
+ if (coff_data(output_bfd)->pe)
{
- if (!process_embedded_commands (input_bfd))
+ if (!process_embedded_commands (output_bfd, finfo->info, input_bfd))
return false;
}
const char *name;
char buf[SYMNMLEN + 1];
- if (isym._n._n_n._n_zeroes == 0
- && isym._n._n_n._n_offset != 0)
- {
- if (strings == NULL)
- {
- strings = coff_read_string_table (input_bfd);
- if (strings == NULL)
- return false;
- }
- name = strings + isym._n._n_n._n_offset;
- }
- else
- {
- memcpy (buf, isym._n._n_name, SYMNMLEN);
- buf[SYMNMLEN] = '\0';
- name = buf;
- }
+ name = _bfd_coff_internal_syment_name (input_bfd, &isym, buf);
+ if (name == NULL)
+ return false;
if ((finfo->info->strip == strip_some
&& (bfd_hash_lookup (finfo->info->keep_hash, name, false,
skip = true;
}
+ /* If this is an enum, struct, or union tag, see if we have
+ already output an identical type. */
+ if (! skip
+ && (finfo->output_bfd->flags & BFD_TRADITIONAL_FORMAT) == 0
+ && (isym.n_sclass == C_ENTAG
+ || isym.n_sclass == C_STRTAG
+ || isym.n_sclass == C_UNTAG)
+ && isym.n_numaux == 1)
+ {
+ const char *name;
+ char buf[SYMNMLEN + 1];
+ struct coff_debug_merge_hash_entry *mh;
+ struct coff_debug_merge_type *mt;
+ union internal_auxent aux;
+ struct coff_debug_merge_element **epp;
+ bfd_byte *esl, *eslend;
+ struct internal_syment *islp;
+ struct coff_debug_merge_type *mtl;
+
+ name = _bfd_coff_internal_syment_name (input_bfd, &isym, buf);
+ if (name == NULL)
+ return false;
+
+ /* Ignore fake names invented by compiler; treat them all as
+ the same name. */
+ if (*name == '~' || *name == '.'
+ || (*name == bfd_get_symbol_leading_char (input_bfd)
+ && (name[1] == '~' || name[1] == '.')))
+ name = "";
+
+ mh = coff_debug_merge_hash_lookup (&finfo->debug_merge, name,
+ true, true);
+ if (mh == NULL)
+ return false;
+
+ /* Allocate memory to hold type information. If this turns
+ out to be a duplicate, we pass this address to
+ bfd_release. */
+ mt = ((struct coff_debug_merge_type *)
+ bfd_alloc (input_bfd,
+ sizeof (struct coff_debug_merge_type)));
+ if (mt == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ mt->class = isym.n_sclass;
+
+ /* Pick up the aux entry, which points to the end of the tag
+ entries. */
+ bfd_coff_swap_aux_in (input_bfd, (PTR) (esym + isymesz),
+ isym.n_type, isym.n_sclass, 0, isym.n_numaux,
+ (PTR) &aux);
+
+ /* Gather the elements. */
+ epp = &mt->elements;
+ mt->elements = NULL;
+ islp = isymp + 2;
+ esl = esym + 2 * isymesz;
+ eslend = ((bfd_byte *) obj_coff_external_syms (input_bfd)
+ + aux.x_sym.x_fcnary.x_fcn.x_endndx.l * isymesz);
+ while (esl < eslend)
+ {
+ const char *elename;
+ char elebuf[SYMNMLEN + 1];
+ char *copy;
+
+ bfd_coff_swap_sym_in (input_bfd, (PTR) esl, (PTR) islp);
+
+ *epp = ((struct coff_debug_merge_element *)
+ bfd_alloc (input_bfd,
+ sizeof (struct coff_debug_merge_element)));
+ if (*epp == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ elename = _bfd_coff_internal_syment_name (input_bfd, islp,
+ elebuf);
+ if (elename == NULL)
+ return false;
+
+ copy = (char *) bfd_alloc (input_bfd, strlen (elename) + 1);
+ if (copy == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ strcpy (copy, elename);
+
+ (*epp)->name = copy;
+ (*epp)->type = islp->n_type;
+ (*epp)->tagndx = 0;
+ if (islp->n_numaux >= 1
+ && islp->n_type != T_NULL
+ && islp->n_sclass != C_EOS)
+ {
+ union internal_auxent eleaux;
+ long indx;
+
+ bfd_coff_swap_aux_in (input_bfd, (PTR) (esl + isymesz),
+ islp->n_type, islp->n_sclass, 0,
+ islp->n_numaux, (PTR) &eleaux);
+ indx = eleaux.x_sym.x_tagndx.l;
+
+ /* FIXME: If this tagndx entry refers to a symbol
+ defined later in this file, we just ignore it.
+ Handling this correctly would be tedious, and may
+ not be required. */
+
+ if (indx > 0
+ && (indx
+ < ((esym -
+ (bfd_byte *) obj_coff_external_syms (input_bfd))
+ / (long) isymesz)))
+ {
+ (*epp)->tagndx = finfo->sym_indices[indx];
+ if ((*epp)->tagndx < 0)
+ (*epp)->tagndx = 0;
+ }
+ }
+ epp = &(*epp)->next;
+ *epp = NULL;
+
+ esl += (islp->n_numaux + 1) * isymesz;
+ islp += islp->n_numaux + 1;
+ }
+
+ /* See if we already have a definition which matches this
+ type. */
+ for (mtl = mh->types; mtl != NULL; mtl = mtl->next)
+ {
+ struct coff_debug_merge_element *me, *mel;
+
+ if (mtl->class != mt->class)
+ continue;
+
+ for (me = mt->elements, mel = mtl->elements;
+ me != NULL && mel != NULL;
+ me = me->next, mel = mel->next)
+ {
+ if (strcmp (me->name, mel->name) != 0
+ || me->type != mel->type
+ || me->tagndx != mel->tagndx)
+ break;
+ }
+
+ if (me == NULL && mel == NULL)
+ break;
+ }
+
+ if (mtl == NULL || (bfd_size_type) mtl->indx >= syment_base)
+ {
+ /* This is the first definition of this type. */
+ mt->indx = output_index;
+ mt->next = mh->types;
+ mh->types = mt;
+ }
+ else
+ {
+ /* This is a redefinition which can be merged. */
+ bfd_release (input_bfd, (PTR) mt);
+ *indexp = mtl->indx;
+ add = (eslend - esym) / isymesz;
+ skip = true;
+ }
+ }
+
/* We now know whether we are to skip this symbol or not. */
if (! skip)
{
bfd_coff_symname_in_debug. That is only true for
XCOFF, and XCOFF requires different linking code
anyhow. */
- BFD_ASSERT (isym._n._n_n._n_offset >= STRING_SIZE_SIZE);
- if (strings == NULL)
- {
- strings = coff_read_string_table (input_bfd);
- if (strings == NULL)
- return false;
- }
- name = strings + isym._n._n_n._n_offset;
+ name = _bfd_coff_internal_syment_name (input_bfd, &isym,
+ (char *) NULL);
+ if (name == NULL)
+ return false;
indx = _bfd_stringtab_add (finfo->strtab, name, hash, copy);
if (indx == (bfd_size_type) -1)
return false;
if (isym.n_sclass == C_FILE)
{
if (finfo->last_file_index != -1
- && finfo->last_file.n_value != output_index)
+ && finfo->last_file.n_value != (long) output_index)
{
/* We must correct the value of the last C_FILE entry. */
finfo->last_file.n_value = output_index;
- if (finfo->last_file_index >= syment_base)
+ if ((bfd_size_type) finfo->last_file_index >= syment_base)
{
/* The last C_FILE symbol is in this input file. */
bfd_coff_swap_sym_out (output_bfd,
add = 1 + isymp->n_numaux;
- if (*indexp < 0
+ if ((*indexp < 0
+ || (bfd_size_type) *indexp < syment_base)
&& (*sym_hash == NULL
|| (*sym_hash)->auxbfd != input_bfd))
esym += add * isymesz;
>= STRING_SIZE_SIZE);
if (strings == NULL)
{
- strings = coff_read_string_table (input_bfd);
+ strings = _bfd_coff_read_string_table (input_bfd);
if (strings == NULL)
return false;
}
}
else if (isymp->n_sclass != C_STAT || isymp->n_type != T_NULL)
{
- long indx;
+ unsigned long indx;
if (ISFCN (isymp->n_type)
|| ISTAG (isymp->n_sclass)
indx = auxp->x_sym.x_tagndx.l;
if (indx > 0 && indx < obj_raw_syment_count (input_bfd))
{
- indx = finfo->sym_indices[indx];
- if (indx < 0)
+ long symindx;
+
+ symindx = finfo->sym_indices[indx];
+ if (symindx < 0)
auxp->x_sym.x_tagndx.l = 0;
else
- auxp->x_sym.x_tagndx.l = indx;
+ auxp->x_sym.x_tagndx.l = symindx;
}
}
bfd_byte *eline;
bfd_byte *elineend;
- if (o->lineno_count == 0)
+ /* FIXME: If SEC_HAS_CONTENTS is not for the section, then
+ build_link_order in ldwrite.c will not have created a
+ link order, which means that we will not have seen this
+ input section in _bfd_coff_final_link, which means that
+ we will not have allocated space for the line numbers of
+ this section. I don't think line numbers can be
+ meaningful for a section which does not have
+ SEC_HAS_CONTENTS set, but, if they do, this must be
+ changed. */
+ if (o->lineno_count == 0
+ || (o->output_section->flags & SEC_HAS_CONTENTS) == 0)
continue;
if (bfd_seek (input_bfd, o->line_filepos, SEEK_SET) != 0
if (iline.l_lnno != 0)
iline.l_addr.l_paddr += offset;
else if (iline.l_addr.l_symndx >= 0
- && (iline.l_addr.l_symndx
+ && ((unsigned long) iline.l_addr.l_symndx
< obj_raw_syment_count (input_bfd)))
{
long indx;
normal case, this will save us from writing out the C_FILE symbol
again. */
if (finfo->last_file_index != -1
- && finfo->last_file_index >= syment_base)
+ && (bfd_size_type) finfo->last_file_index >= syment_base)
{
finfo->last_file.n_value = output_index;
bfd_coff_swap_sym_out (output_bfd, (PTR) &finfo->last_file,
if (bfd_seek (output_bfd,
obj_sym_filepos (output_bfd) + syment_base * osymesz,
SEEK_SET) != 0
- || bfd_write (finfo->outsyms, outsym - finfo->outsyms, 1,
- output_bfd) != outsym - finfo->outsyms)
+ || (bfd_write (finfo->outsyms, outsym - finfo->outsyms, 1,
+ output_bfd)
+ != (bfd_size_type) (outsym - finfo->outsyms)))
return false;
BFD_ASSERT ((obj_raw_syment_count (output_bfd)
}
/* Relocate the contents of each section. */
- relsz = bfd_coff_relsz (input_bfd);
adjust_symndx = coff_backend_info (input_bfd)->_bfd_coff_adjust_symndx;
for (o = input_bfd->sections; o != NULL; o = o->next)
{
+ bfd_byte *contents;
+
if ((o->flags & SEC_HAS_CONTENTS) == 0)
- continue;
+ {
+ if ((o->flags & SEC_RELOC) != 0
+ && o->reloc_count != 0)
+ {
+ ((*_bfd_error_handler)
+ ("%s: relocs in section `%s', but it has no contents",
+ bfd_get_filename (input_bfd),
+ bfd_get_section_name (input_bfd, o)));
+ bfd_set_error (bfd_error_no_contents);
+ return false;
+ }
- if (! bfd_get_section_contents (input_bfd, o, finfo->contents,
- (file_ptr) 0, o->_raw_size))
- return false;
+ continue;
+ }
+
+ if (coff_section_data (input_bfd, o) != NULL
+ && coff_section_data (input_bfd, o)->contents != NULL)
+ contents = coff_section_data (input_bfd, o)->contents;
+ else
+ {
+ if (! bfd_get_section_contents (input_bfd, o, finfo->contents,
+ (file_ptr) 0, o->_raw_size))
+ return false;
+ contents = finfo->contents;
+ }
if ((o->flags & SEC_RELOC) != 0)
{
int target_index;
struct internal_reloc *internal_relocs;
- bfd_byte *erel;
- bfd_byte *erel_end;
struct internal_reloc *irel;
/* Read in the relocs. */
- if (bfd_seek (input_bfd, o->rel_filepos, SEEK_SET) != 0
- || (bfd_read (finfo->external_relocs, relsz, o->reloc_count,
- input_bfd) != relsz * o->reloc_count))
- return false;
-
- /* If we are doing a relocateable link, we keep the swapped
- in relocs in memory, and don't write them out until the
- end of the link. */
target_index = o->output_section->target_index;
- if (! finfo->info->relocateable)
- internal_relocs = finfo->internal_relocs;
- else
- internal_relocs = (finfo->section_info[target_index].relocs
- + o->output_section->reloc_count);
-
- /* Swap in the relocs. */
- erel = finfo->external_relocs;
- erel_end = erel + relsz * o->reloc_count;
- irel = internal_relocs;
- for (; erel < erel_end; erel += relsz, irel++)
- bfd_coff_swap_reloc_in (input_bfd, (PTR) erel, (PTR) irel);
+ internal_relocs = (_bfd_coff_read_internal_relocs
+ (input_bfd, o, false, finfo->external_relocs,
+ finfo->info->relocateable,
+ (finfo->info->relocateable
+ ? (finfo->section_info[target_index].relocs
+ + o->output_section->reloc_count)
+ : finfo->internal_relocs)));
+ if (internal_relocs == NULL)
+ return false;
/* Call processor specific code to relocate the section
contents. */
if (! bfd_coff_relocate_section (output_bfd, finfo->info,
input_bfd, o,
- finfo->contents,
+ contents,
internal_relocs,
finfo->internal_syms,
finfo->sec_ptrs))
worth it. */
is = finfo->internal_syms + irel->r_symndx;
- if (is->_n._n_n._n_zeroes == 0
- && is->_n._n_n._n_offset != 0)
- {
- if (strings == NULL)
- {
- strings = coff_read_string_table (input_bfd);
- if (strings == NULL)
- return false;
- }
- name = strings + is->_n._n_n._n_offset;
- }
- else
- {
- memcpy (buf, is->_n._n_name, SYMNMLEN);
- buf[SYMNMLEN] = '\0';
- name = buf;
- }
+ name = (_bfd_coff_internal_syment_name
+ (input_bfd, is, buf));
+ if (name == NULL)
+ return false;
if (! ((*finfo->info->callbacks->unattached_reloc)
(finfo->info, name, input_bfd, o,
/* Write out the modified section contents. */
if (! bfd_set_section_contents (output_bfd, o->output_section,
- finfo->contents, o->output_offset,
+ contents, o->output_offset,
(o->_cooked_size != 0
? o->_cooked_size
: o->_raw_size)))
if (! finfo->info->keep_memory)
{
- if (! coff_link_free_symbols (input_bfd))
+ if (! _bfd_coff_free_symbols (input_bfd))
return false;
}
struct internal_reloc *rel;
struct internal_reloc *relend;
-
rel = relocs;
relend = rel + input_section->reloc_count;
for (; rel < relend; rel++)
if (howto == NULL)
return false;
- /* WINDOWS_NT; in this next section, the value of 'val' will be computed.
- With respect to the .idata and .rsrc sections, the NT_IMAGE_BASE
- must be removed from the value that is to be relocated (NT_IMAGE_BASE
- is currently defined in internal.h and has value 400000). Now this
- value should only be removed from addresses being relocated in the
- .idata and .rsrc sections, not the .text section which should have
- the 'real' address. In addition, the .rsrc val's must also be
- adjusted by the input_section->vma. */
-
val = 0;
if (h == NULL)
{
asection *sec;
- int i;
if (symndx == -1)
{
+ sec->output_offset
+ sym->n_value
- sec->vma);
- if (obj_pe (output_bfd))
- {
- /* Make a correction here to val if the sec is either .rsrc$nnn
- or .idata$nnn or reloc or edata */
- if (strcmp (input_section->name, ".text") != 0)
- {
- if (strncmp (sec->name, ".idata$", 7) == 0
- || strcmp (sec->name, ".reloc") == 0
- || strcmp (sec->name, ".edata") == 0)
- val -= NT_IMAGE_BASE;
- else if (strncmp (sec->name, ".rsrc$", 6) == 0)
- {
- val -= NT_IMAGE_BASE;
- val += sec->vma;
- }
- }
- }
}
}
else
val = (h->root.u.def.value
+ sec->output_section->vma
+ sec->output_offset);
- if (obj_pe (output_bfd)) {
- /* Make a correction here to val if the sec is either .rsrc$nnn
- or .idata$nnnn or reloc or edata. */
- if (strcmp (input_section->name, ".text") != 0)
- {
- if (strncmp (sec->name, ".idata$", 7) == 0
- || strcmp (sec->name, ".reloc") == 0
- || strcmp (sec->name, ".edata") == 0)
- val -= NT_IMAGE_BASE;
- else if (strncmp (sec->name, ".rsrc$", 6) == 0)
- {
- val -= NT_IMAGE_BASE;
- val += sec->vma;
- }
- }
}
- }
+
else if (! info->relocateable)
{
if (! ((*info->callbacks->undefined_symbol)
}
}
- if (obj_pe (output_bfd)) {
-
- /* Here's where we will collect the information about the dll .idata$4
- and 5 entries and fix up the vals for .idata$2 information. When
- we encounter processing for .idata$5 (this could also be done for
- .idata$4) we will keep track of the number of entries made for a
- particular dll. Now if we are processing .idata$2 input_section,
- then we know how many entries have been made from each dll and we
- have to fix up the .idata$2 start addresses for .idata$4 and
- .idata$5. */
- add_to_val = 0;
- if (strncmp (input_section->name, ".idata$5", 8) == 0)
- {
- if (num_DLLs == 0) /* this is the first one */
- {
- num_DLLs += 1;
- MS_DLL[num_DLLs].DLL_name = input_bfd->filename;
- MS_DLL[num_DLLs].num_entries += 1;
- }
- else if (!strcmp (input_bfd->filename, MS_DLL[num_DLLs].DLL_name))
- {
- /* this is just another entry */
- MS_DLL[num_DLLs].num_entries += 1;
- }
- else
- {
- /* This is a new DLL */
- num_DLLs += 1;
- MS_DLL[num_DLLs].DLL_name = input_bfd->filename;
- MS_DLL[num_DLLs].num_entries += 1;
- }
- all_entries += 1;
- }
-
- else if (strncmp (input_section->name, ".idata$2", 8) == 0)
- {
- /* All information about the number of entries needed from each
- DLL has been collected at this point. Now we actually want to
- make and adjustment to the val's for .idata$4 and .idata$5
- which are part of the .idata$2 section. */
- /* first we have to get the symbol name from sym. This will be
- either .idata$4, .idata$5 or .idata$6. A 'fixup' is computed for
- .idata$4 and .idata$5 but not for .idata$6 (this value is handled
- correctly already and doesn't have to be fixed) */
- const char *name;
- char buf[SYMNMLEN + 1];
-
- if (sym->_n._n_n._n_zeroes == 0 && sym->_n._n_n._n_offset != 0)
- name = obj_coff_strings (input_bfd) + sym->_n._n_n._n_offset;
- else
- {
- strncpy (buf, sym->_n._n_name, SYMNMLEN);
- buf[SYMNMLEN] = '\0';
- name = buf;
- }
-
- if (num_DLLs_done)
- {
- /* we have done at least one. The val fixups are based on the
- previous fixups */
- if (strncmp (name, ".idata$4", 8) == 0)
- {
- add_to_val = idata_4_prev +
- ((MS_DLL[num_DLLs_done].num_entries + 1) * 4);
- idata_4_prev = add_to_val;
- }
- else if (strncmp (name, ".idata$5", 8) == 0)
- {
- add_to_val = idata_5_prev +
- ((MS_DLL[num_DLLs_done].num_entries + 1) * 4);
- idata_5_prev = add_to_val;
- num_DLLs_done += 1; /* assuming that idata$5 is done after $4*/
- }
- }
- else
- {
- /* This is the first one. The other idata$4 and 5 entries will be
- computed from these */
- if (strncmp (name, ".idata$4", 8) == 0)
- {
- add_to_val = ((num_DLLs - 1) * 0x14) + 0x28;
- idata_4_prev = add_to_val;
- }
- else if (strncmp (name, ".idata$5", 8) == 0)
- {
- add_to_val = idata_4_prev + (all_entries + num_DLLs) * 4;
- idata_5_prev = add_to_val;
- num_DLLs_done += 1; /* assuming that idata$5 is done after $4*/
- }
-
- }
- }
- val = val + add_to_val;
-
- }
-
if (info->base_file)
{
- /* So if this is non pcrelative, and is referenced
- to a section or a common symbol, then it needs a reloc */
- if (!howto->pc_relative
- && (sym->n_scnum
- || sym->n_value))
+ /* Emit a reloc if the backend thinks it needs it. */
+ if (sym && pe_data(output_bfd)->in_reloc_p(output_bfd, howto))
{
/* relocation to a symbol in a section which
isn't absolute - we output the address here
to a file */
bfd_vma addr = rel->r_vaddr
+ - input_section->vma
+ input_section->output_offset
+ input_section->output_section->vma;
+ if (coff_data(output_bfd)->pe)
+ addr -= pe_data(output_bfd)->pe_opthdr.ImageBase;
fwrite (&addr, 1,4, (FILE *) info->base_file);
}
}
name = "*ABS*";
else if (h != NULL)
name = h->root.root.string;
- else if (sym->_n._n_n._n_zeroes == 0
- && sym->_n._n_n._n_offset != 0)
- name = obj_coff_strings (input_bfd) + sym->_n._n_n._n_offset;
else
{
- strncpy (buf, sym->_n._n_name, SYMNMLEN);
- buf[SYMNMLEN] = '\0';
- name = buf;
+ name = _bfd_coff_internal_syment_name (input_bfd, sym, buf);
+ if (name == NULL)
+ return false;
}
if (! ((*info->callbacks->reloc_overflow)
}
}
}
-
return true;
}
+