[PATCH 3/4] bfd/COFF: propagate function size when copying/linking ELF objects
Jan Beulich
jbeulich@suse.com
Fri Mar 28 14:51:34 GMT 2025
While COFF, unlike ELF, doesn't have a generic way to express symbol
size, there is a means to do so for functions. When inputs are ELF,
propagate function sizes, including the fact that a symbol denotes a
function, to the output's symbol table.
Note that this requires hackery (cross-object-format processing) in two
places - when linking, global symbols are entered into a global hash
table, and hence relevant information needs to be kept there in that
case, while otherwise the original symbol structures can be consulted.
For the setting of ->u.syment.n_type the later writing of the field to
literal 0 needs to be dropped from coff_write_alien_symbol(). It was
redundant anyway with an earlier write of the field using C_NUL.
---
It may be possible to do this without COFF hackery in elflink.c: We
could move "size" from struct elf_link_hash_entry to struct
bfd_link_hash_entry, add "flags" (BSF_*) there as well, and have symbol
size (as available) be passed into _bfd_generic_link_add_one_symbol().
This latter adjustment would be intrusive, even if largely mechanical.
It could then be _bfd_coff_final_link()'s loop over "foreign" symbols
which would instantiate the auxiliary entry structure. (This may then
also be more amenable to later correctly setting the "next" indices in
the auxiliary structures.) Thoughts anyone as to what's preferable? It's
the intrusiveness which made me not try this route right away.
--- a/bfd/coffgen.c
+++ b/bfd/coffgen.c
@@ -42,6 +42,7 @@
#include "libbfd.h"
#include "coff/internal.h"
#include "libcoff.h"
+#include "elf-bfd.h"
#include "hashtab.h"
/* Extract a long section name at STRINDEX and copy it to the bfd objstack.
@@ -1270,9 +1271,24 @@ coff_write_alien_symbol (bfd *abfd,
if (c != (coff_symbol_type *) NULL)
native->u.syment.n_flags = bfd_asymbol_bfd (&c->symbol)->flags;
}
+
+ const elf_symbol_type *elfsym = elf_symbol_from (symbol);
+ if (elfsym
+ && (symbol->flags & BSF_FUNCTION)
+ && elfsym->internal_elf_sym.st_size)
+ {
+ /* coff_data (abfd)->local_n_btshft is what ought to be used here,
+ just that it's set only when reading in COFF objects. */
+ native->u.syment.n_type = DT_FCN << 4;
+ native->u.syment.n_numaux = 1;
+ native[1].u.auxent.x_sym.x_misc.x_fsize
+ = elfsym->internal_elf_sym.st_size;
+ /* FIXME .u.auxent.x_sym.x_fcnary.x_fcn.x_endndx would better also
+ be set, which would require updating the field once the next
+ function is seen. */
+ }
}
- native->u.syment.n_type = 0;
if (symbol->flags & BSF_FILE)
native->u.syment.n_sclass = C_FILE;
else if (symbol->flags & BSF_LOCAL)
--- a/bfd/cofflink.c
+++ b/bfd/cofflink.c
@@ -127,12 +127,18 @@ _bfd_coff_link_hash_table_init (struct c
const char *),
unsigned int entsize)
{
+ bool ret;
+
memset (&table->stab_info, 0, sizeof (table->stab_info));
- return bfd_hash_table_init (&table->decoration_hash,
- _decoration_hash_newfunc,
- sizeof (struct decoration_hash_entry))
- &&_bfd_link_hash_table_init (&table->root, abfd, newfunc, entsize);
+ ret = bfd_hash_table_init (&table->decoration_hash,
+ _decoration_hash_newfunc,
+ sizeof (struct decoration_hash_entry))
+ && _bfd_link_hash_table_init (&table->root, abfd, newfunc, entsize);
+
+ table->root.type = bfd_link_coff_hash_table;
+
+ return ret;
}
/* Create a COFF linker hash table. */
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -24,6 +24,8 @@
#include "libbfd.h"
#define ARCH_SIZE 0
#include "elf-bfd.h"
+#include "coff/internal.h"
+#include "libcoff.h"
#include "safe-ctype.h"
#include "libiberty.h"
#include "objalloc.h"
@@ -5714,6 +5716,25 @@ elf_link_add_object_symbols (bfd *abfd,
elf_link_add_to_first_hash (abfd, info, name, must_copy_name);
}
}
+ else if (!dynamic && definition
+ && is_coff_hash_table (&htab->root)
+ && ELF_ST_TYPE (isym->st_info) == STT_FUNC
+ && isym->st_size)
+ {
+ struct coff_link_hash_entry *coff = (struct coff_link_hash_entry *)h;
+
+ /* coff_data (info->output_bfd)->local_n_btshft is what ought to be
+ used here, just that it's set only when reading in COFF objects. */
+ coff->type = DT_FCN << 4;
+ coff->aux = bfd_zalloc (info->output_bfd, sizeof (*coff->aux));
+ if ( coff->aux )
+ {
+ coff->numaux = 1;
+ coff->aux->x_sym.x_misc.x_fsize = isym->st_size;
+ /* FIXME ->x_sym.x_fcnary.x_fcn.x_endndx would better also be
+ set, yet that would need to happen elsewhere anyway. */
+ }
+ }
}
if (info->lto_plugin_active
--- a/bfd/libcoff.h
+++ b/bfd/libcoff.h
@@ -339,6 +339,10 @@ struct coff_reloc_cookie
(bool (*) (struct bfd_link_hash_entry *, void *)) (func), \
(info)))
+/* Yields TRUE if the hash table is a struct coff_link_hash_table. */
+
+#define is_coff_hash_table(htab) ((htab)->type == bfd_link_coff_hash_table)
+
/* Get the COFF linker hash table from a link_info structure. */
#define coff_hash_table(p) ((struct coff_link_hash_table *) ((p)->hash))
--- a/bfd/libcoff-in.h
+++ b/bfd/libcoff-in.h
@@ -335,6 +335,10 @@ struct coff_reloc_cookie
(bool (*) (struct bfd_link_hash_entry *, void *)) (func), \
(info)))
+/* Yields TRUE if the hash table is a struct coff_link_hash_table. */
+
+#define is_coff_hash_table(htab) ((htab)->type == bfd_link_coff_hash_table)
+
/* Get the COFF linker hash table from a link_info structure. */
#define coff_hash_table(p) ((struct coff_link_hash_table *) ((p)->hash))
--- a/include/bfdlink.h
+++ b/include/bfdlink.h
@@ -63,7 +63,8 @@ enum bfd_link_elf_stt_common
enum bfd_link_hash_table_type
{
bfd_link_generic_hash_table,
- bfd_link_elf_hash_table
+ bfd_link_elf_hash_table,
+ bfd_link_coff_hash_table,
};
/* These are the possible types of an entry in the BFD link hash
More information about the Binutils
mailing list