diff options
Diffstat (limited to 'bfd')
-rw-r--r-- | bfd/Makefile.in | 4 | ||||
-rw-r--r-- | bfd/archures.c | 1 | ||||
-rw-r--r-- | bfd/bfd-in2.h | 8 | ||||
-rw-r--r-- | bfd/bfd.c | 3 | ||||
-rw-r--r-- | bfd/coffgen.c | 22 | ||||
-rw-r--r-- | bfd/doc/chew.c | 62 | ||||
-rw-r--r-- | bfd/doc/local.mk | 4 | ||||
-rw-r--r-- | bfd/ecoff.c | 8 | ||||
-rw-r--r-- | bfd/elf-bfd.h | 2 | ||||
-rw-r--r-- | bfd/elf-eh-frame.c | 2 | ||||
-rw-r--r-- | bfd/elf.c | 170 | ||||
-rw-r--r-- | bfd/elf32-arm.c | 104 | ||||
-rw-r--r-- | bfd/elf32-i386.c | 56 | ||||
-rw-r--r-- | bfd/elf32-v850.c | 7 | ||||
-rw-r--r-- | bfd/elf64-x86-64.c | 149 | ||||
-rw-r--r-- | bfd/elflink.c | 52 | ||||
-rw-r--r-- | bfd/elfnn-loongarch.c | 548 | ||||
-rw-r--r-- | bfd/elfnn-riscv.c | 2 | ||||
-rw-r--r-- | bfd/elfxx-riscv.c | 46 | ||||
-rw-r--r-- | bfd/elfxx-target.h | 11 | ||||
-rw-r--r-- | bfd/elfxx-x86.c | 133 | ||||
-rw-r--r-- | bfd/elfxx-x86.h | 7 | ||||
-rw-r--r-- | bfd/libbfd-in.h | 42 | ||||
-rw-r--r-- | bfd/libbfd.c | 47 | ||||
-rw-r--r-- | bfd/libbfd.h | 42 | ||||
-rw-r--r-- | bfd/merge.c | 177 | ||||
-rw-r--r-- | bfd/pdb.c | 57 | ||||
-rw-r--r-- | bfd/peXXigen.c | 4 | ||||
-rw-r--r-- | bfd/pef.c | 8 | ||||
-rw-r--r-- | bfd/peicode.h | 162 | ||||
-rw-r--r-- | bfd/plugin.c | 28 | ||||
-rw-r--r-- | bfd/syms.c | 12 | ||||
-rw-r--r-- | bfd/tekhex.c | 81 | ||||
-rw-r--r-- | bfd/version.h | 2 | ||||
-rw-r--r-- | bfd/vms-alpha.c | 46 |
35 files changed, 1300 insertions, 809 deletions
diff --git a/bfd/Makefile.in b/bfd/Makefile.in index b3d97d4..38364f4 100644 --- a/bfd/Makefile.in +++ b/bfd/Makefile.in @@ -1322,7 +1322,7 @@ REGEN_TEXI = \ $(MKDOC) -f $(srcdir)/doc/doc.str < $< > $@.tmp; \ texi=$@; \ texi=$${texi%.stamp}.texi; \ - test -e $$texi || test ! -f $(srcdir)/$$texi || $(LN_S) $(srcdir)/$$texi .; \ + test -e $$texi || test ! -f $(srcdir)/$$texi || $(LN_S) $(srcdir)/$$texi $$texi; \ $(SHELL) $(srcdir)/../move-if-change $@.tmp $$texi; \ touch $@; \ ) @@ -2497,7 +2497,7 @@ coff-tic54x.lo: coff-tic54x.c $(MKDOC): doc/chew.stamp ; @true doc/chew.stamp: $(srcdir)/doc/chew.c doc/$(am__dirstamp) $(AM_V_CCLD)$(CC_FOR_BUILD) -o doc/chw$$$$$(EXEEXT_FOR_BUILD) $(CFLAGS_FOR_BUILD) \ - $(CPPFLAGS_FOR_BUILD) $(LDFLAGS_FOR_BUILD) \ + $(WARN_CFLAGS_FOR_BUILD) $(CPPFLAGS_FOR_BUILD) $(LDFLAGS_FOR_BUILD) \ -I. -I$(srcdir) -Idoc -I$(srcdir)/../include -I$(srcdir)/../intl -I../intl \ $(srcdir)/doc/chew.c && \ $(SHELL) $(srcdir)/../move-if-change \ diff --git a/bfd/archures.c b/bfd/archures.c index 94118b8..c4decc5 100644 --- a/bfd/archures.c +++ b/bfd/archures.c @@ -947,6 +947,7 @@ bfd_arch_get_compatible (const bfd *abfd, to assume that they know what they are doing. */ if (accept_unknowns || ubfd->plugin_format == bfd_plugin_yes + || ubfd->plugin_format == bfd_plugin_yes_unused || strcmp (bfd_get_target (ubfd), "binary") == 0) return kbfd->arch_info; return NULL; diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index e3b5a8b..3b047d9 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -1260,6 +1260,11 @@ typedef struct _symbol_info const char *stab_name; /* String for stab type. */ } symbol_info; +/* An empty string that will not match the address of any other + symbol name, even unnamed local symbols which will also have empty + string names. This can be used to flag a symbol as corrupt if its + name uses an out of range string table index. */ +extern const char bfd_symbol_error_name[]; #define bfd_get_symtab_upper_bound(abfd) \ BFD_SEND (abfd, _bfd_get_symtab_upper_bound, (abfd)) @@ -1947,7 +1952,8 @@ enum bfd_plugin_format { bfd_plugin_unknown = 0, bfd_plugin_yes = 1, - bfd_plugin_no = 2 + bfd_plugin_yes_unused = 2, + bfd_plugin_no = 3 }; struct bfd_build_id @@ -65,7 +65,8 @@ EXTERNAL . { . bfd_plugin_unknown = 0, . bfd_plugin_yes = 1, -. bfd_plugin_no = 2 +. bfd_plugin_yes_unused = 2, +. bfd_plugin_no = 3 . }; . .struct bfd_build_id diff --git a/bfd/coffgen.c b/bfd/coffgen.c index cc1c655..5754dbb 100644 --- a/bfd/coffgen.c +++ b/bfd/coffgen.c @@ -1928,7 +1928,7 @@ coff_get_normalized_symtab (bfd *abfd) if ((bfd_size_type) aux->u.auxent.x_file.x_n.x_n.x_offset >= obj_coff_strings_len (abfd)) sym->u.syment._n._n_n._n_offset = - (uintptr_t) _("<corrupt>"); + (uintptr_t) bfd_symbol_error_name; else sym->u.syment._n._n_n._n_offset = (uintptr_t) (string_table @@ -1978,7 +1978,7 @@ coff_get_normalized_symtab (bfd *abfd) if ((bfd_size_type) aux->u.auxent.x_file.x_n.x_n.x_offset >= obj_coff_strings_len (abfd)) aux->u.auxent.x_file.x_n.x_n.x_offset = - (uintptr_t) _("<corrupt>"); + (uintptr_t) bfd_symbol_error_name; else aux->u.auxent.x_file.x_n.x_n.x_offset = (uintptr_t) (string_table @@ -2028,7 +2028,7 @@ coff_get_normalized_symtab (bfd *abfd) } if (sym->u.syment._n._n_n._n_offset >= obj_coff_strings_len (abfd)) sym->u.syment._n._n_n._n_offset = - (uintptr_t) _("<corrupt>"); + (uintptr_t) bfd_symbol_error_name; else sym->u.syment._n._n_n._n_offset = (uintptr_t) (string_table @@ -2047,7 +2047,7 @@ coff_get_normalized_symtab (bfd *abfd) the debug data. */ if (sym->u.syment._n._n_n._n_offset >= debug_sec->size) sym->u.syment._n._n_n._n_offset = - (uintptr_t) _("<corrupt>"); + (uintptr_t) bfd_symbol_error_name; else sym->u.syment._n._n_n._n_offset = (uintptr_t) (debug_sec_data @@ -2161,11 +2161,13 @@ coff_print_symbol (bfd *abfd, bfd_print_symbol_type how) { FILE * file = (FILE *) filep; + const char *symname = (symbol->name != bfd_symbol_error_name + ? symbol->name : _("<corrupt>")); switch (how) { case bfd_print_symbol_name: - fprintf (file, "%s", symbol->name); + fprintf (file, "%s", symname); break; case bfd_print_symbol_more: @@ -2189,7 +2191,7 @@ coff_print_symbol (bfd *abfd, if (combined < obj_raw_syments (abfd) || combined >= obj_raw_syments (abfd) + obj_raw_syment_count (abfd)) { - fprintf (file, _("<corrupt info> %s"), symbol->name); + fprintf (file, _("<corrupt info> %s"), symname); break; } @@ -2207,7 +2209,7 @@ coff_print_symbol (bfd *abfd, combined->u.syment.n_sclass, combined->u.syment.n_numaux); bfd_fprintf_vma (abfd, file, val); - fprintf (file, " %s", symbol->name); + fprintf (file, " %s", symname); for (aux = 0; aux < combined->u.syment.n_numaux; aux++) { @@ -2297,7 +2299,9 @@ coff_print_symbol (bfd *abfd, if (l) { - fprintf (file, "\n%s :", l->u.sym->name); + fprintf (file, "\n%s :", + l->u.sym->name != bfd_symbol_error_name + ? l->u.sym->name : _("<corrupt>")); l++; while (l->line_number) { @@ -2317,7 +2321,7 @@ coff_print_symbol (bfd *abfd, symbol->section->name, coffsymbol (symbol)->native ? "n" : "g", coffsymbol (symbol)->lineno ? "l" : " ", - symbol->name); + symname); } } } diff --git a/bfd/doc/chew.c b/bfd/doc/chew.c index 842d415..469bd80 100644 --- a/bfd/doc/chew.c +++ b/bfd/doc/chew.c @@ -132,8 +132,8 @@ int warning; string_type stack[STACK]; string_type *tos; -unsigned int idx = 0; /* Pos in input buffer */ -string_type *ptr; /* and the buffer */ +unsigned int pos_idx = 0; /* Pos in input buffer */ +string_type *buf_ptr; /* and the buffer */ intptr_t istack[STACK]; intptr_t *isp = &istack[0]; @@ -149,7 +149,7 @@ die (char *msg) exit (1); } -void * +static void * xmalloc (size_t size) { void *newmem; @@ -163,7 +163,7 @@ xmalloc (size_t size) return newmem; } -void * +static void * xrealloc (void *oldmem, size_t size) { void *newmem; @@ -180,7 +180,7 @@ xrealloc (void *oldmem, size_t size) return newmem; } -char * +static char * xstrdup (const char *s) { size_t len = strlen (s) + 1; @@ -202,22 +202,6 @@ init_string (string_type *buffer) init_string_with_size (buffer, DEF_SIZE); } -static int -find (string_type *str, char *what) -{ - unsigned int i; - char *p; - p = what; - for (i = 0; i < str->write_idx && *p; i++) - { - if (*p == str->ptr[i]) - p++; - else - p = what; - } - return (*p == 0); -} - static void write_buffer (string_type *buffer, FILE *f) { @@ -853,7 +837,7 @@ icopy_past_newline (void) tos++; check_range (); init_string (tos); - idx = copy_past_newline (ptr, idx, tos); + pos_idx = copy_past_newline (buf_ptr, pos_idx, tos); pc++; } @@ -1046,11 +1030,11 @@ get_stuff_in_command (void) check_range (); init_string (tos); - while (at (ptr, idx)) + while (at (buf_ptr, pos_idx)) { - if (iscommand (ptr, idx)) + if (iscommand (buf_ptr, pos_idx)) break; - idx = copy_past_newline (ptr, idx, tos); + pos_idx = copy_past_newline (buf_ptr, pos_idx, tos); } pc++; } @@ -1089,7 +1073,7 @@ icatstr (void) static void skip_past_newline (void) { - idx = skip_past_newline_1 (ptr, idx); + pos_idx = skip_past_newline_1 (buf_ptr, pos_idx); pc++; } @@ -1120,7 +1104,7 @@ catstrif (void) pc++; } -char * +static char * nextword (char *string, char **word) { char *word_start; @@ -1208,7 +1192,7 @@ nextword (char *string, char **word) return NULL; } -dict_type * +static dict_type * lookup_word (char *word) { dict_type *ptr = root; @@ -1261,15 +1245,15 @@ perform (void) { tos = stack; - while (at (ptr, idx)) + while (at (buf_ptr, pos_idx)) { /* It's worth looking through the command list. */ - if (iscommand (ptr, idx)) + if (iscommand (buf_ptr, pos_idx)) { char *next; dict_type *word; - (void) nextword (addr (ptr, idx), &next); + (void) nextword (addr (buf_ptr, pos_idx), &next); word = lookup_word (next); @@ -1281,16 +1265,16 @@ perform (void) { if (warning) fprintf (stderr, "warning, %s is not recognised\n", next); - idx = skip_past_newline_1 (ptr, idx); + pos_idx = skip_past_newline_1 (buf_ptr, pos_idx); } free (next); } else - idx = skip_past_newline_1 (ptr, idx); + pos_idx = skip_past_newline_1 (buf_ptr, pos_idx); } } -dict_type * +static dict_type * newentry (char *word) { dict_type *new_d = xmalloc (sizeof (*new_d)); @@ -1303,7 +1287,7 @@ newentry (char *word) return new_d; } -unsigned int +static unsigned int add_to_definition (dict_type *entry, pcu word) { if (entry->code_end == entry->code_length) @@ -1317,7 +1301,7 @@ add_to_definition (dict_type *entry, pcu word) return entry->code_end++; } -void +static void add_intrinsic (char *name, void (*func) (void)) { dict_type *new_d = newentry (xstrdup (name)); @@ -1345,7 +1329,7 @@ add_intrinsic_variable (const char *name, intptr_t *loc) add_variable (xstrdup (name), loc); } -void +static void compile (char *string) { /* Add words to the dictionary. */ @@ -1539,7 +1523,7 @@ main (int ac, char *av[]) init_string (&pptr); init_string (stack + 0); tos = stack + 1; - ptr = &pptr; + buf_ptr = &pptr; add_intrinsic ("push_text", push_text); add_intrinsic ("!", bang); @@ -1583,7 +1567,7 @@ main (int ac, char *av[]) catchar (&buffer, '\n'); read_in (&buffer, stdin); - remove_noncomments (&buffer, ptr); + remove_noncomments (&buffer, buf_ptr); for (i = 1; i < (unsigned int) ac; i++) { if (av[i][0] == '-') diff --git a/bfd/doc/local.mk b/bfd/doc/local.mk index 5e8f486..346dba3 100644 --- a/bfd/doc/local.mk +++ b/bfd/doc/local.mk @@ -80,7 +80,7 @@ MKDOC = %D%/chew$(EXEEXT_FOR_BUILD) $(MKDOC): %D%/chew.stamp ; @true %D%/chew.stamp: $(srcdir)/%D%/chew.c %D%/$(am__dirstamp) $(AM_V_CCLD)$(CC_FOR_BUILD) -o %D%/chw$$$$$(EXEEXT_FOR_BUILD) $(CFLAGS_FOR_BUILD) \ - $(CPPFLAGS_FOR_BUILD) $(LDFLAGS_FOR_BUILD) \ + $(WARN_CFLAGS_FOR_BUILD) $(CPPFLAGS_FOR_BUILD) $(LDFLAGS_FOR_BUILD) \ -I. -I$(srcdir) -I%D% -I$(srcdir)/../include -I$(srcdir)/../intl -I../intl \ $(srcdir)/%D%/chew.c && \ $(SHELL) $(srcdir)/../move-if-change \ @@ -101,7 +101,7 @@ REGEN_TEXI = \ $(MKDOC) -f $(srcdir)/%D%/doc.str < $< > $@.tmp; \ texi=$@; \ texi=$${texi%.stamp}.texi; \ - test -e $$texi || test ! -f $(srcdir)/$$texi || $(LN_S) $(srcdir)/$$texi .; \ + test -e $$texi || test ! -f $(srcdir)/$$texi || $(LN_S) $(srcdir)/$$texi $$texi; \ $(SHELL) $(srcdir)/../move-if-change $@.tmp $$texi; \ touch $@; \ ) diff --git a/bfd/ecoff.c b/bfd/ecoff.c index 0450176..d0cb9e1 100644 --- a/bfd/ecoff.c +++ b/bfd/ecoff.c @@ -1452,11 +1452,13 @@ _bfd_ecoff_print_symbol (bfd *abfd, const struct ecoff_debug_swap * const debug_swap = &ecoff_backend (abfd)->debug_swap; FILE *file = (FILE *)filep; + const char *symname = (symbol->name != bfd_symbol_error_name + ? symbol->name : _("<corrupt>")); switch (how) { case bfd_print_symbol_name: - fprintf (file, "%s", symbol->name); + fprintf (file, "%s", symname); break; case bfd_print_symbol_more: if (ecoffsymbol (symbol)->local) @@ -1526,7 +1528,7 @@ _bfd_ecoff_print_symbol (bfd *abfd, (unsigned) ecoff_ext.asym.sc, (unsigned) ecoff_ext.asym.index, jmptbl, cobol_main, weakext, - symbol->name); + symname); if (ecoffsymbol (symbol)->fdr != NULL && ecoff_ext.asym.index != indexNil) @@ -3278,8 +3280,8 @@ ecoff_link_hash_newfunc (struct bfd_hash_entry *entry, ret->abfd = NULL; ret->written = 0; ret->small = 0; + memset ((void *) &ret->esym, 0, sizeof ret->esym); } - memset ((void *) &ret->esym, 0, sizeof ret->esym); return (struct bfd_hash_entry *) ret; } diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index b89d3dd..96cf119 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -2540,7 +2540,7 @@ extern long _bfd_elf_link_lookup_local_dynindx extern bool _bfd_elf_compute_section_file_positions (bfd *, struct bfd_link_info *); extern file_ptr _bfd_elf_assign_file_position_for_section - (Elf_Internal_Shdr *, file_ptr, bool); + (Elf_Internal_Shdr *, file_ptr, bool, unsigned char); extern bool _bfd_elf_modify_headers (bfd *, struct bfd_link_info *); diff --git a/bfd/elf-eh-frame.c b/bfd/elf-eh-frame.c index 902d7c1..ebe162f 100644 --- a/bfd/elf-eh-frame.c +++ b/bfd/elf-eh-frame.c @@ -345,7 +345,7 @@ next_cie_fde_offset (const struct eh_cie_fde *ent, static bool skip_cfa_op (bfd_byte **iter, bfd_byte *end, unsigned int encoded_ptr_width) { - bfd_byte op; + bfd_byte op = 0; bfd_vma length; if (!read_byte (iter, end, &op)) @@ -285,26 +285,22 @@ bfd_elf_get_str_section (bfd *abfd, unsigned int shindex) offset = i_shdrp[shindex]->sh_offset; shstrtabsize = i_shdrp[shindex]->sh_size; - /* Allocate and clear an extra byte at the end, to prevent crashes - in case the string table is not terminated. */ - if (shstrtabsize + 1 <= 1 + if (shstrtabsize == 0 || bfd_seek (abfd, offset, SEEK_SET) != 0 - || (shstrtab - = _bfd_mmap_readonly_persistent (abfd, shstrtabsize)) == NULL) + || (shstrtab = _bfd_mmap_persistent (abfd, shstrtabsize)) == NULL) { /* Once we've failed to read it, make sure we don't keep trying. Otherwise, we'll keep allocating space for the string table over and over. */ i_shdrp[shindex]->sh_size = 0; } - else if (shstrtab[shstrtabsize - 1] != '\0') + else if (shstrtab[shstrtabsize - 1] != 0) { /* It is an error if a string table isn't terminated. */ _bfd_error_handler /* xgettext:c-format */ - (_("%pB(%pA): string table is corrupt"), - abfd, i_shdrp[shindex]->bfd_section); - return NULL; + (_("%pB: string table [%u] is corrupt"), abfd, shindex); + shstrtab[shstrtabsize - 1] = 0; } i_shdrp[shindex]->contents = shstrtab; } @@ -524,21 +520,19 @@ bfd_elf_get_elf_syms (bfd *ibfd, } out1: - _bfd_munmap_readonly_temporary (alloc_extshndx, alloc_extshndx_size); + _bfd_munmap_temporary (alloc_extshndx, alloc_extshndx_size); out2: - _bfd_munmap_readonly_temporary (alloc_ext, alloc_ext_size); + _bfd_munmap_temporary (alloc_ext, alloc_ext_size); return intsym_buf; } /* Look up a symbol name. */ -const char * -bfd_elf_sym_name (bfd *abfd, - Elf_Internal_Shdr *symtab_hdr, - Elf_Internal_Sym *isym, - asection *sym_sec) +static const char * +bfd_elf_sym_name_raw (bfd *abfd, + Elf_Internal_Shdr *symtab_hdr, + Elf_Internal_Sym *isym) { - const char *name; unsigned int iname = isym->st_name; unsigned int shindex = symtab_hdr->sh_link; @@ -550,9 +544,18 @@ bfd_elf_sym_name (bfd *abfd, shindex = elf_elfheader (abfd)->e_shstrndx; } - name = bfd_elf_string_from_elf_section (abfd, shindex, iname); + return bfd_elf_string_from_elf_section (abfd, shindex, iname); +} + +const char * +bfd_elf_sym_name (bfd *abfd, + Elf_Internal_Shdr *symtab_hdr, + Elf_Internal_Sym *isym, + asection *sym_sec) +{ + const char *name = bfd_elf_sym_name_raw (abfd, symtab_hdr, isym); if (name == NULL) - name = "(null)"; + name = bfd_symbol_error_name; else if (sym_sec && *name == '\0') name = bfd_section_name (sym_sec); @@ -585,7 +588,7 @@ group_signature (bfd *abfd, Elf_Internal_Shdr *ghdr) &isym, esym, &eshndx) == NULL) return NULL; - return bfd_elf_sym_name (abfd, hdr, &isym, NULL); + return bfd_elf_sym_name_raw (abfd, hdr, &isym); } static bool @@ -1736,8 +1739,7 @@ get_hash_table_data (bfd *abfd, bfd_size_type number, return NULL; } - e_data = _bfd_mmap_readonly_temporary (abfd, size, &e_data_addr, - &e_data_size); + e_data = _bfd_mmap_temporary (abfd, size, &e_data_addr, &e_data_size); if (e_data == NULL) return NULL; @@ -1755,7 +1757,7 @@ get_hash_table_data (bfd *abfd, bfd_size_type number, while (number--) i_data[number] = bfd_get_64 (abfd, e_data + number * ent_size); - _bfd_munmap_readonly_temporary (e_data_addr, e_data_size); + _bfd_munmap_temporary (e_data_addr, e_data_size); return i_data; } @@ -1826,8 +1828,7 @@ _bfd_elf_get_dynamic_symbols (bfd *abfd, Elf_Internal_Phdr *phdr, goto error_return; dynbuf_size = phdr->p_filesz; - dynbuf = _bfd_mmap_readonly_temporary (abfd, dynbuf_size, - &dynbuf_addr, &dynbuf_size); + dynbuf = _bfd_mmap_temporary (abfd, dynbuf_size, &dynbuf_addr, &dynbuf_size); if (dynbuf == NULL) goto error_return; @@ -1905,7 +1906,7 @@ _bfd_elf_get_dynamic_symbols (bfd *abfd, Elf_Internal_Phdr *phdr, goto error_return; /* Dynamic string table must be valid until ABFD is closed. */ - strbuf = (char *) _bfd_mmap_readonly_persistent (abfd, dt_strsz); + strbuf = (char *) _bfd_mmap_persistent (abfd, dt_strsz); if (strbuf == NULL) goto error_return; if (strbuf[dt_strsz - 1] != 0) @@ -1914,7 +1915,7 @@ _bfd_elf_get_dynamic_symbols (bfd *abfd, Elf_Internal_Phdr *phdr, _bfd_error_handler /* xgettext:c-format */ (_("%pB: DT_STRTAB table is corrupt"), abfd); - goto error_return; + strbuf[dt_strsz - 1] = 0; } /* Get the real symbol count from DT_HASH or DT_GNU_HASH. Prefer @@ -2091,9 +2092,8 @@ _bfd_elf_get_dynamic_symbols (bfd *abfd, Elf_Internal_Phdr *phdr, || bfd_seek (abfd, filepos, SEEK_SET) != 0) goto error_return; esymbuf_size = amt; - esymbuf = _bfd_mmap_readonly_temporary (abfd, esymbuf_size, - &esymbuf_addr, - &esymbuf_size); + esymbuf = _bfd_mmap_temporary (abfd, esymbuf_size, + &esymbuf_addr, &esymbuf_size); if (esymbuf == NULL) goto error_return; @@ -2137,7 +2137,7 @@ _bfd_elf_get_dynamic_symbols (bfd *abfd, Elf_Internal_Phdr *phdr, goto error_return; /* DT_VERSYM info must be valid until ABFD is closed. */ - versym = _bfd_mmap_readonly_persistent (abfd, amt); + versym = _bfd_mmap_persistent (abfd, amt); if (dt_verdef) { @@ -2149,7 +2149,7 @@ _bfd_elf_get_dynamic_symbols (bfd *abfd, Elf_Internal_Phdr *phdr, goto error_return; /* DT_VERDEF info must be valid until ABFD is closed. */ - verdef = _bfd_mmap_readonly_persistent (abfd, verdef_size); + verdef = _bfd_mmap_persistent (abfd, verdef_size); } if (dt_verneed) @@ -2162,7 +2162,7 @@ _bfd_elf_get_dynamic_symbols (bfd *abfd, Elf_Internal_Phdr *phdr, goto error_return; /* DT_VERNEED info must be valid until ABFD is closed. */ - verneed = _bfd_mmap_readonly_persistent (abfd, verneed_size); + verneed = _bfd_mmap_persistent (abfd, verneed_size); } } @@ -2185,8 +2185,8 @@ _bfd_elf_get_dynamic_symbols (bfd *abfd, Elf_Internal_Phdr *phdr, /* Restore file position for elf_object_p. */ if (bfd_seek (abfd, saved_filepos, SEEK_SET) != 0) res = false; - _bfd_munmap_readonly_temporary (dynbuf_addr, dynbuf_size); - _bfd_munmap_readonly_temporary (esymbuf_addr, esymbuf_size); + _bfd_munmap_temporary (dynbuf_addr, dynbuf_size); + _bfd_munmap_temporary (esymbuf_addr, esymbuf_size); free (gnubuckets); free (gnuchains); free (mipsxlat); @@ -2316,10 +2316,13 @@ bfd_elf_print_symbol (bfd *abfd, bfd_print_symbol_type how) { FILE *file = (FILE *) filep; + const char *symname = (symbol->name != bfd_symbol_error_name + ? symbol->name : _("<corrupt>")); + switch (how) { case bfd_print_symbol_name: - fprintf (file, "%s", symbol->name); + fprintf (file, "%s", symname); break; case bfd_print_symbol_more: fprintf (file, "elf "); @@ -2342,11 +2345,10 @@ bfd_elf_print_symbol (bfd *abfd, if (bed->elf_backend_print_symbol_all) name = (*bed->elf_backend_print_symbol_all) (abfd, filep, symbol); - if (name == NULL) - { - name = symbol->name; - bfd_print_symbol_vandf (abfd, file, symbol); - } + if (name != NULL) + symname = name; + else + bfd_print_symbol_vandf (abfd, file, symbol); fprintf (file, " %s\t", section_name); /* Print the "other" value for a symbol. For common symbols, @@ -2393,7 +2395,7 @@ bfd_elf_print_symbol (bfd *abfd, fprintf (file, " 0x%02x", (unsigned int) st_other); } - fprintf (file, " %s", name); + fprintf (file, " %s", symname); } break; } @@ -4550,25 +4552,29 @@ elf_map_symbols (bfd *abfd, unsigned int *pnum_locals) return true; } -/* Align to the maximum file alignment that could be required for any - ELF data structure. */ - -static inline file_ptr -align_file_position (file_ptr off, int align) -{ - return (off + align - 1) & ~(align - 1); -} - /* Assign a file position to a section, optionally aligning to the required section alignment. */ file_ptr _bfd_elf_assign_file_position_for_section (Elf_Internal_Shdr *i_shdrp, file_ptr offset, - bool align) + bool align, + unsigned char log_file_align) { - if (align && i_shdrp->sh_addralign > 1) - offset = BFD_ALIGN (offset, i_shdrp->sh_addralign & -i_shdrp->sh_addralign); + if (i_shdrp->sh_addralign > 1) + { + file_ptr salign = i_shdrp->sh_addralign & -i_shdrp->sh_addralign; + + if (align) + offset = BFD_ALIGN (offset, salign); + else if (log_file_align) + { + /* Heuristic: Cap alignment at log_file_align. */ + file_ptr falign = 1u << log_file_align; + + offset = BFD_ALIGN (offset, salign < falign ? salign : falign); + } + } i_shdrp->sh_offset = offset; if (i_shdrp->bfd_section != NULL) i_shdrp->bfd_section->filepos = offset; @@ -4656,18 +4662,18 @@ _bfd_elf_compute_section_file_positions (bfd *abfd, off = elf_next_file_pos (abfd); hdr = & elf_symtab_hdr (abfd); - off = _bfd_elf_assign_file_position_for_section (hdr, off, true); + off = _bfd_elf_assign_file_position_for_section (hdr, off, true, 0); if (elf_symtab_shndx_list (abfd) != NULL) { hdr = & elf_symtab_shndx_list (abfd)->hdr; if (hdr->sh_size != 0) - off = _bfd_elf_assign_file_position_for_section (hdr, off, true); + off = _bfd_elf_assign_file_position_for_section (hdr, off, true, 0); /* FIXME: What about other symtab_shndx sections in the list ? */ } hdr = &elf_tdata (abfd)->strtab_hdr; - off = _bfd_elf_assign_file_position_for_section (hdr, off, true); + off = _bfd_elf_assign_file_position_for_section (hdr, off, true, 0); elf_next_file_pos (abfd) = off; @@ -6541,8 +6547,8 @@ assign_file_positions_for_non_load_sections (bfd *abfd, else align = hdr->sh_addralign & -hdr->sh_addralign; off += vma_page_aligned_bias (hdr->sh_addr, off, align); - off = _bfd_elf_assign_file_position_for_section (hdr, off, - false); + off = _bfd_elf_assign_file_position_for_section (hdr, off, false, + bed->s->log_file_align); } else if (((hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA) && hdr->bfd_section == NULL) @@ -6559,7 +6565,7 @@ assign_file_positions_for_non_load_sections (bfd *abfd, || hdr == i_shdrpp[elf_shstrtab_sec (abfd)]) hdr->sh_offset = -1; else - off = _bfd_elf_assign_file_position_for_section (hdr, off, true); + off = _bfd_elf_assign_file_position_for_section (hdr, off, true, 0); } elf_next_file_pos (abfd) = off; @@ -6796,7 +6802,8 @@ assign_file_positions_except_relocs (bfd *abfd, hdr->sh_offset = -1; } else - off = _bfd_elf_assign_file_position_for_section (hdr, off, true); + off = _bfd_elf_assign_file_position_for_section (hdr, off, false, + 0); } elf_next_file_pos (abfd) = off; @@ -7011,7 +7018,7 @@ _bfd_elf_assign_file_positions_for_non_load (bfd *abfd) Elf_Internal_Shdr **shdrpp, **end_shdrpp; Elf_Internal_Shdr *shdrp; Elf_Internal_Ehdr *i_ehdrp; - const struct elf_backend_data *bed; + const struct elf_backend_data *bed = get_elf_backend_data (abfd); /* Skip non-load sections without section header. */ if ((abfd->flags & BFD_NO_SECTION_HEADER) != 0) @@ -7079,7 +7086,10 @@ _bfd_elf_assign_file_positions_for_non_load (bfd *abfd) sec->contents = NULL; } - off = _bfd_elf_assign_file_position_for_section (shdrp, off, true); + off = _bfd_elf_assign_file_position_for_section (shdrp, off, + (abfd->flags & (EXEC_P | DYNAMIC)) + || bfd_get_format (abfd) == bfd_core, + bed->s->log_file_align); } } @@ -7088,12 +7098,11 @@ _bfd_elf_assign_file_positions_for_non_load (bfd *abfd) _bfd_elf_strtab_finalize (elf_shstrtab (abfd)); shdrp = &elf_tdata (abfd)->shstrtab_hdr; shdrp->sh_size = _bfd_elf_strtab_size (elf_shstrtab (abfd)); - off = _bfd_elf_assign_file_position_for_section (shdrp, off, true); + off = _bfd_elf_assign_file_position_for_section (shdrp, off, true, 0); /* Place the section headers. */ i_ehdrp = elf_elfheader (abfd); - bed = get_elf_backend_data (abfd); - off = align_file_position (off, 1 << bed->s->log_file_align); + off = BFD_ALIGN (off, 1u << bed->s->log_file_align); i_ehdrp->e_shoff = off; off += i_ehdrp->e_shnum * i_ehdrp->e_shentsize; elf_next_file_pos (abfd) = off; @@ -8732,17 +8741,16 @@ swap_out_syms (bfd *abfd, && (flags & (BSF_SECTION_SYM | BSF_GLOBAL)) == BSF_SECTION_SYM) { /* Local section symbols have no name. */ - sym.st_name = (unsigned long) -1; + sym.st_name = 0; } else { /* Call _bfd_elf_strtab_offset after _bfd_elf_strtab_finalize to get the final offset for st_name. */ - sym.st_name - = (unsigned long) _bfd_elf_strtab_add (stt, syms[idx]->name, - false); - if (sym.st_name == (unsigned long) -1) + size_t stridx = _bfd_elf_strtab_add (stt, syms[idx]->name, false); + if (stridx == (size_t) -1) goto error_return; + sym.st_name = stridx; } bfd_vma value = syms[idx]->value; @@ -8953,9 +8961,7 @@ Unable to handle section index %x in ELF symbol. Using ABS instead."), for (idx = 0; idx < outbound_syms_index; idx++) { struct elf_sym_strtab *elfsym = &symstrtab[idx]; - if (elfsym->sym.st_name == (unsigned long) -1) - elfsym->sym.st_name = 0; - else + if (elfsym->sym.st_name != 0) elfsym->sym.st_name = _bfd_elf_strtab_offset (stt, elfsym->sym.st_name); if (info && info->callbacks->ctf_new_symbol) @@ -9294,9 +9300,8 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bool default_imported_symver) if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0) goto error_return_verref; contents_size = hdr->sh_size; - contents = _bfd_mmap_readonly_temporary (abfd, contents_size, - &contents_addr, - &contents_size); + contents = _bfd_mmap_temporary (abfd, contents_size, + &contents_addr, &contents_size); if (contents == NULL) goto error_return_verref; @@ -9429,7 +9434,7 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bool default_imported_symver) elf_tdata (abfd)->cverrefs = i; if (contents != elf_tdata (abfd)->dt_verneed) - _bfd_munmap_readonly_temporary (contents_addr, contents_size); + _bfd_munmap_temporary (contents_addr, contents_size); contents = NULL; contents_addr = NULL; } @@ -9473,9 +9478,8 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bool default_imported_symver) if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0) goto error_return_verdef; contents_size = hdr->sh_size; - contents = _bfd_mmap_readonly_temporary (abfd, contents_size, - &contents_addr, - &contents_size); + contents = _bfd_mmap_temporary (abfd, contents_size, + &contents_addr, &contents_size); if (contents == NULL) goto error_return_verdef; @@ -9629,7 +9633,7 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bool default_imported_symver) } if (contents != elf_tdata (abfd)->dt_verdef) - _bfd_munmap_readonly_temporary (contents_addr, contents_size); + _bfd_munmap_temporary (contents_addr, contents_size); contents = NULL; contents_addr = NULL; } @@ -9687,7 +9691,7 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bool default_imported_symver) error_return: if (contents != elf_tdata (abfd)->dt_verneed && contents != elf_tdata (abfd)->dt_verdef) - _bfd_munmap_readonly_temporary (contents_addr, contents_size); + _bfd_munmap_temporary (contents_addr, contents_size); return false; } diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c index ca76bee..17df8b3 100644 --- a/bfd/elf32-arm.c +++ b/bfd/elf32-arm.c @@ -4226,12 +4226,33 @@ arm_type_of_stub (struct bfd_link_info *info, r_type = ELF32_R_TYPE (rel->r_info); + /* Don't pretend we know what stub to use (if any) when we target a + Thumb-only target and we don't know the actual destination + type. */ + if (branch_type == ST_BRANCH_UNKNOWN && thumb_only) + return stub_type; + /* ST_BRANCH_TO_ARM is nonsense to thumb-only targets when we are considering a function call relocation. */ if (thumb_only && (r_type == R_ARM_THM_CALL || r_type == R_ARM_THM_JUMP24 || r_type == R_ARM_THM_JUMP19) && branch_type == ST_BRANCH_TO_ARM) - branch_type = ST_BRANCH_TO_THUMB; + { + if (sym_sec == bfd_abs_section_ptr) + /* As an exception, assume that absolute symbols are of the + right kind (Thumb). They are presumably defined in the + linker script, where it is not possible to declare them as + Thumb (and thus are seen as Arm mode). We'll inform the + user with a warning, though, in + elf32_arm_final_link_relocate. */ + branch_type = ST_BRANCH_TO_THUMB; + else + /* Otherwise do not silently build a stub, and let the users + know they have to fix their code. Indeed, we could decide + to insert a stub involving Arm code and/or BLX, leading to + a run-time crash. */ + return stub_type; + } /* For TLS call relocs, it is the caller's responsibility to provide the address of the appropriate trampoline. */ @@ -10382,14 +10403,6 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, else addend = signed_addend = rel->r_addend; - /* ST_BRANCH_TO_ARM is nonsense to thumb-only targets when we - are resolving a function call relocation. */ - if (using_thumb_only (globals) - && (r_type == R_ARM_THM_CALL - || r_type == R_ARM_THM_JUMP24) - && branch_type == ST_BRANCH_TO_ARM) - branch_type = ST_BRANCH_TO_THUMB; - /* Record the symbol information that should be used in dynamic relocations. */ dynreloc_st_type = st_type; @@ -10452,6 +10465,73 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, gotplt_offset = (bfd_vma) -1; } + /* ST_BRANCH_TO_ARM is nonsense to thumb-only targets when we are + resolving a function call relocation. We want to inform the user + that something is wrong. */ + if (using_thumb_only (globals) + && (r_type == R_ARM_THM_CALL + || r_type == R_ARM_THM_JUMP24) + && branch_type == ST_BRANCH_TO_ARM + /* Calls through a PLT are special: the assembly source code + cannot be annotated with '.type foo(PLT), %function', and + they handled specifically below anyway. */ + && splt == NULL) + { + if (sym_sec == bfd_abs_section_ptr) + { + /* As an exception, assume that absolute symbols are of the + right kind (Thumb). They are presumably defined in the + linker script, where it is not possible to declare them as + Thumb (and thus are seen as Arm mode). Inform the user with + a warning, though. */ + branch_type = ST_BRANCH_TO_THUMB; + + if (sym_sec->owner) + _bfd_error_handler + (_("warning: %pB(%s): Forcing bramch to absolute symbol in Thumb mode (Thumb-only CPU)" + " in %pB"), + sym_sec->owner, sym_name, input_bfd); + else + _bfd_error_handler + (_("warning: (%s): Forcing branch to absolute symbol in Thumb mode (Thumb-only CPU)" + " in %pB"), + sym_name, input_bfd); + } + else + /* Otherwise do not silently build a stub, and let the users + know they have to fix their code. Indeed, we could decide + to insert a stub involving Arm code and/or BLX, leading to + a run-time crash. */ + branch_type = ST_BRANCH_UNKNOWN; + } + + /* Fail early if branch_type is ST_BRANCH_UNKNOWN and we target a + Thumb-only CPU. We could emit a warning on Arm-capable targets + too, but that would be too verbose (a lot of legacy code does not + use the .type foo, %function directive). */ + if (using_thumb_only (globals) + && (r_type == R_ARM_THM_CALL + || r_type == R_ARM_THM_JUMP24) + && branch_type == ST_BRANCH_UNKNOWN + /* Exception to the rule above: a branch to an undefined weak + symbol is turned into a jump to the next instruction unless a + PLT entry will be created (see below). */ + && !(h && h->root.type == bfd_link_hash_undefweak + && plt_offset == (bfd_vma) -1)) + { + if (sym_sec != NULL + && sym_sec->owner != NULL) + _bfd_error_handler + (_("%pB(%s): Unknown destination type (ARM/Thumb) in %pB"), + sym_sec->owner, sym_name, input_bfd); + else + _bfd_error_handler + (_("(%s): Unknown destination type (ARM/Thumb) in %pB"), + sym_name, input_bfd); + + return bfd_reloc_notsupported; + } + resolved_to_zero = (h != NULL && UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)); @@ -17838,7 +17918,7 @@ elf32_arm_output_map_sym (output_arch_syminfo *osi, sym.st_other = 0; sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_NOTYPE); sym.st_shndx = osi->sec_shndx; - sym.st_target_internal = 0; + sym.st_target_internal = ST_BRANCH_TO_ARM; elf32_arm_section_map_add (osi->sec, names[type][1], offset); return osi->func (osi->flaginfo, names[type], &sym, osi->sec, NULL) == 1; } @@ -17995,7 +18075,7 @@ elf32_arm_output_stub_sym (output_arch_syminfo *osi, const char *name, sym.st_other = 0; sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FUNC); sym.st_shndx = osi->sec_shndx; - sym.st_target_internal = 0; + sym.st_target_internal = ST_BRANCH_TO_ARM; return osi->func (osi->flaginfo, name, &sym, osi->sec, NULL) == 1; } @@ -19743,7 +19823,7 @@ elf32_arm_swap_symbol_in (bfd * abfd, { if (!bfd_elf32_swap_symbol_in (abfd, psrc, pshn, dst)) return false; - dst->st_target_internal = 0; + dst->st_target_internal = ST_BRANCH_TO_ARM; /* New EABI objects mark thumb function symbols by setting the low bit of the address. */ diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index 7d573e7..2e8d595 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -975,15 +975,15 @@ elf_i386_check_tls_transition (asection *sec, case R_386_TLS_IE: /* Check transition from IE access model: - movl foo@indntpoff(%rip), %eax - movl foo@indntpoff(%rip), %reg - addl foo@indntpoff(%rip), %reg + movl foo@indntpoff, %eax + movl foo@indntpoff, %reg + addl foo@indntpoff, %reg */ if (offset < 1 || (offset + 4) > sec->size) return elf_x86_tls_error_yes; - /* Check "movl foo@tpoff(%rip), %eax" first. */ + /* Check "movl foo@indntpoff, %eax" first. */ val = bfd_get_8 (abfd, contents + offset - 1); if (val == 0xa1) return elf_x86_tls_error_none; @@ -991,7 +991,7 @@ elf_i386_check_tls_transition (asection *sec, if (offset < 2) return elf_x86_tls_error_yes; - /* Check movl|addl foo@tpoff(%rip), %reg. */ + /* Check movl|addl foo@indntpoff, %reg. */ type = bfd_get_8 (abfd, contents + offset - 2); if (type != 0x8b && type != 0x03) return elf_x86_tls_error_add_mov; @@ -1039,19 +1039,8 @@ elf_i386_check_tls_transition (asection *sec, : elf_x86_tls_error_yes); case R_386_TLS_DESC_CALL: - /* Check transition from GDesc access model: - call *x@tlsdesc(%eax) - */ - if (offset + 2 <= sec->size) - { - /* Make sure that it's a call *x@tlsdesc(%eax). */ - call = contents + offset; - return (call[0] == 0xff && call[1] == 0x10 - ? elf_x86_tls_error_none - : elf_x86_tls_error_indirect_call); - } - - return elf_x86_tls_error_yes; + /* It has been checked in elf_i386_tls_transition. */ + return elf_x86_tls_error_none; default: abort (); @@ -1077,6 +1066,8 @@ elf_i386_tls_transition (struct bfd_link_info *info, bfd *abfd, unsigned int to_type = from_type; bool check = true; unsigned int to_le_type, to_ie_type; + bfd_vma offset; + bfd_byte *call; /* Skip TLS transition for functions. */ if (h != NULL @@ -1098,9 +1089,34 @@ elf_i386_tls_transition (struct bfd_link_info *info, bfd *abfd, switch (from_type) { + case R_386_TLS_DESC_CALL: + /* Check valid GDesc call: + call *x@tlscall(%eax) + */ + offset = rel->r_offset; + call = NULL; + if (offset + 2 <= sec->size) + { + /* Make sure that it's a call *x@tlscall(%eax). */ + call = contents + offset; + if (call[0] != 0xff || call[1] != 0x10) + call = NULL; + } + + if (call == NULL) + { + _bfd_x86_elf_link_report_tls_transition_error + (info, abfd, sec, symtab_hdr, h, sym, rel, + "R_386_TLS_DESC_CALL", NULL, + elf_x86_tls_error_indirect_call); + + return false; + } + + /* Fall through. */ + case R_386_TLS_GD: case R_386_TLS_GOTDESC: - case R_386_TLS_DESC_CALL: case R_386_TLS_IE_32: case R_386_TLS_IE: case R_386_TLS_GOTIE: @@ -1707,7 +1723,7 @@ elf_i386_scan_relocs (bfd *abfd, name = h->root.root.string; else name = bfd_elf_sym_name (abfd, symtab_hdr, isym, - NULL); + NULL); _bfd_error_handler /* xgettext:c-format */ (_("%pB: `%s' accessed both as normal and " diff --git a/bfd/elf32-v850.c b/bfd/elf32-v850.c index 85cbcbc..bb3ce8d 100644 --- a/bfd/elf32-v850.c +++ b/bfd/elf32-v850.c @@ -1933,8 +1933,11 @@ v850_elf_info_to_howto_rela (bfd *abfd, static bool v850_elf_is_local_label_name (bfd *abfd ATTRIBUTE_UNUSED, const char *name) { - return ( (name[0] == '.' && (name[1] == 'L' || name[1] == '.')) - || (name[0] == '_' && name[1] == '.' && name[2] == 'L' && name[3] == '_')); + if (name[0] == '.' && (name[1] == 'L' || name[1] == '.')) + return true; + if (name[0] == '_' && name[1] == '.' && name[2] == 'L' && name[3] == '_') + return true; + return false; } static bool diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index 83399ea..a62fa62 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -906,6 +906,14 @@ static const sframe_frame_row_entry elf_x86_64_sframe_pltn_fre2 = SFRAME_V1_FRE_INFO (SFRAME_BASE_REG_SP, 1, SFRAME_FRE_OFFSET_1B) /* FRE info. */ }; +/* .sframe FRE covering the .plt section entry for IBT. */ +static const sframe_frame_row_entry elf_x86_64_sframe_ibt_pltn_fre2 = +{ + 9, /* SFrame FRE start address. */ + {16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 12 bytes. */ + SFRAME_V1_FRE_INFO (SFRAME_BASE_REG_SP, 1, SFRAME_FRE_OFFSET_1B) /* FRE info. */ +}; + /* .sframe FRE covering the second .plt section entry. */ static const sframe_frame_row_entry elf_x86_64_sframe_sec_pltn_fre1 = { @@ -914,7 +922,7 @@ static const sframe_frame_row_entry elf_x86_64_sframe_sec_pltn_fre1 = SFRAME_V1_FRE_INFO (SFRAME_BASE_REG_SP, 1, SFRAME_FRE_OFFSET_1B) /* FRE info. */ }; -/* SFrame helper object for non-lazy PLT. Also used for IBT enabled PLT. */ +/* SFrame helper object for non-lazy PLT. */ static const struct elf_x86_sframe_plt elf_x86_64_sframe_non_lazy_plt = { LAZY_PLT_ENTRY_SIZE, @@ -927,10 +935,34 @@ static const struct elf_x86_sframe_plt elf_x86_64_sframe_non_lazy_plt = { &elf_x86_64_sframe_sec_pltn_fre1, &elf_x86_64_sframe_null_fre }, 0, 0, /* There is no second PLT necessary. */ - { &elf_x86_64_sframe_null_fre } + { &elf_x86_64_sframe_null_fre }, + NON_LAZY_PLT_ENTRY_SIZE, + 1, /* Number of FREs for PLT GOT. */ + /* Array of SFrame FREs for PLT GOT. */ + { &elf_x86_64_sframe_null_fre }, +}; + +/* SFrame helper object for non-lazy IBT enabled PLT. */ +static const struct elf_x86_sframe_plt elf_x86_64_sframe_non_lazy_ibt_plt = +{ + LAZY_PLT_ENTRY_SIZE, + 2, /* Number of FREs for PLT0. */ + /* Array of SFrame FREs for plt0. */ + { &elf_x86_64_sframe_plt0_fre1, &elf_x86_64_sframe_plt0_fre2 }, + LAZY_PLT_ENTRY_SIZE, + 1, /* Number of FREs for PLTn. */ + /* Array of SFrame FREs for plt. */ + { &elf_x86_64_sframe_sec_pltn_fre1, &elf_x86_64_sframe_null_fre }, + 0, + 0, /* There is no second PLT necessary. */ + { &elf_x86_64_sframe_null_fre }, + LAZY_PLT_ENTRY_SIZE, + 1, /* Number of FREs for PLT GOT. */ + /* Array of SFrame FREs for PLT GOT. */ + { &elf_x86_64_sframe_null_fre }, }; -/* SFrame helper object for lazy PLT. Also used for IBT enabled PLT. */ +/* SFrame helper object for lazy PLT. */ static const struct elf_x86_sframe_plt elf_x86_64_sframe_plt = { LAZY_PLT_ENTRY_SIZE, @@ -942,10 +974,34 @@ static const struct elf_x86_sframe_plt elf_x86_64_sframe_plt = /* Array of SFrame FREs for plt. */ { &elf_x86_64_sframe_pltn_fre1, &elf_x86_64_sframe_pltn_fre2 }, NON_LAZY_PLT_ENTRY_SIZE, - 1, /* Number of FREs for PLTn for second PLT. */ - /* FREs for second plt (stack trace info for .plt.got is - identical). Used when IBT or non-lazy PLT is in effect. */ - { &elf_x86_64_sframe_sec_pltn_fre1 } + 1, /* Number of FREs for second PLT. */ + /* Array of SFrame FREs for second PLT. */ + { &elf_x86_64_sframe_sec_pltn_fre1 }, + NON_LAZY_PLT_ENTRY_SIZE, + 1, /* Number of FREs for PLT GOT. */ + /* Array of SFrame FREs for PLT GOT. */ + { &elf_x86_64_sframe_null_fre }, +}; + +/* SFrame helper object for lazy PLT with IBT. */ +static const struct elf_x86_sframe_plt elf_x86_64_sframe_ibt_plt = +{ + LAZY_PLT_ENTRY_SIZE, + 2, /* Number of FREs for PLT0. */ + /* Array of SFrame FREs for plt0. */ + { &elf_x86_64_sframe_plt0_fre1, &elf_x86_64_sframe_plt0_fre2 }, + LAZY_PLT_ENTRY_SIZE, + 2, /* Number of FREs for PLTn. */ + /* Array of SFrame FREs for plt. */ + { &elf_x86_64_sframe_pltn_fre1, &elf_x86_64_sframe_ibt_pltn_fre2 }, + LAZY_PLT_ENTRY_SIZE, + 1, /* Number of FREs for second PLT. */ + /* Array of SFrame FREs for second plt. */ + { &elf_x86_64_sframe_sec_pltn_fre1 }, + LAZY_PLT_ENTRY_SIZE, + 1, /* Number of FREs for PLT GOT. */ + /* Array of SFrame FREs for PLT GOT. */ + { &elf_x86_64_sframe_null_fre }, }; /* These are the standard parameters. */ @@ -1409,32 +1465,8 @@ elf_x86_64_check_tls_transition (bfd *abfd, : elf_x86_tls_error_yes); case R_X86_64_TLSDESC_CALL: - /* Check transition from GDesc access model: - call *x@tlsdesc(%rax) <--- LP64 mode. - call *x@tlsdesc(%eax) <--- X32 mode. - */ - if (offset + 2 <= sec->size) - { - unsigned int prefix; - call = contents + offset; - prefix = 0; - if (!ABI_64_P (abfd)) - { - /* Check for call *x@tlsdesc(%eax). */ - if (call[0] == 0x67) - { - prefix = 1; - if (offset + 3 > sec->size) - return elf_x86_tls_error_yes; - } - } - /* Make sure that it's a call *x@tlsdesc(%rax). */ - return (call[prefix] == 0xff && call[1 + prefix] == 0x10 - ? elf_x86_tls_error_none - : elf_x86_tls_error_indirect_call); - } - - return elf_x86_tls_error_yes; + /* It has been checked in elf_x86_64_tls_transition. */ + return elf_x86_tls_error_none; default: abort (); @@ -1459,6 +1491,8 @@ elf_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd, unsigned int from_type = *r_type; unsigned int to_type = from_type; bool check = true; + bfd_vma offset; + bfd_byte *call; /* Skip TLS transition for functions. */ if (h != NULL @@ -1468,10 +1502,49 @@ elf_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd, switch (from_type) { + case R_X86_64_TLSDESC_CALL: + /* Check valid GDesc call: + call *x@tlscall(%rax) <--- LP64 mode. + call *x@tlscall(%eax) <--- X32 mode. + */ + offset = rel->r_offset; + call = NULL; + if (offset + 2 <= sec->size) + { + unsigned int prefix; + call = contents + offset; + prefix = 0; + if (!ABI_64_P (abfd)) + { + /* Check for call *x@tlscall(%eax). */ + if (call[0] == 0x67) + { + prefix = 1; + if (offset + 3 > sec->size) + call = NULL; + } + } + + /* Make sure that it's a call *x@tlscall(%rax). */ + if (call != NULL + && (call[prefix] != 0xff || call[1 + prefix] != 0x10)) + call = NULL; + } + + if (call == NULL) + { + _bfd_x86_elf_link_report_tls_transition_error + (info, abfd, sec, symtab_hdr, h, sym, rel, + "R_X86_64_TLSDESC_CALL", NULL, + elf_x86_tls_error_indirect_call); + return false; + } + + /* Fall through. */ + case R_X86_64_TLSGD: case R_X86_64_GOTPC32_TLSDESC: case R_X86_64_CODE_4_GOTPC32_TLSDESC: - case R_X86_64_TLSDESC_CALL: case R_X86_64_GOTTPOFF: case R_X86_64_CODE_4_GOTTPOFF: case R_X86_64_CODE_6_GOTTPOFF: @@ -3825,7 +3898,7 @@ elf_x86_64_relocate_section (bfd *output_bfd, unsigned int prefix = 0; if (!ABI_64_P (input_bfd)) { - /* Check for call *x@tlsdesc(%eax). */ + /* Check for call *x@tlscall(%eax). */ if (contents[roff] == 0x67) prefix = 1; } @@ -4285,7 +4358,7 @@ elf_x86_64_relocate_section (bfd *output_bfd, unsigned int prefix = 0; if (!ABI_64_P (input_bfd)) { - /* Check for call *x@tlsdesc(%eax). */ + /* Check for call *x@tlscall(%eax). */ if (contents[roff] == 0x67) prefix = 1; } @@ -5661,8 +5734,8 @@ elf_x86_64_link_setup_gnu_properties (struct bfd_link_info *info) { init_table.sframe_lazy_plt = &elf_x86_64_sframe_plt; init_table.sframe_non_lazy_plt = &elf_x86_64_sframe_non_lazy_plt; - init_table.sframe_lazy_ibt_plt = &elf_x86_64_sframe_plt; - init_table.sframe_non_lazy_ibt_plt = &elf_x86_64_sframe_non_lazy_plt; + init_table.sframe_lazy_ibt_plt = &elf_x86_64_sframe_ibt_plt; + init_table.sframe_non_lazy_ibt_plt = &elf_x86_64_sframe_non_lazy_ibt_plt; } else { diff --git a/bfd/elflink.c b/bfd/elflink.c index a180e59..ef159da 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -64,7 +64,7 @@ _bfd_elf_link_keep_memory (struct bfd_link_info *info) this is opt-in by each backend. */ const struct elf_backend_data *bed = get_elf_backend_data (info->output_bfd); - if (bed->use_mmap) + if (bed != NULL && bed->use_mmap) return false; #endif bfd *abfd; @@ -2877,7 +2877,7 @@ _bfd_elf_link_info_read_relocs (bfd *abfd, if (keep_memory) esdo->relocs = internal_relocs; - _bfd_munmap_readonly_temporary (alloc1, alloc1_size); + _bfd_munmap_temporary (alloc1, alloc1_size); /* Don't free alloc2, since if it was allocated we are passing it back (under the name of internal_relocs). */ @@ -2885,7 +2885,7 @@ _bfd_elf_link_info_read_relocs (bfd *abfd, return internal_relocs; error_return: - _bfd_munmap_readonly_temporary (alloc1, alloc1_size); + _bfd_munmap_temporary (alloc1, alloc1_size); if (alloc2 != NULL) { if (keep_memory) @@ -3653,6 +3653,7 @@ elf_link_is_defined_archive_symbol (bfd * abfd, carsym * symdef) object file is an IR object, give linker LTO plugin a chance to get the correct symbol table. */ if (abfd->plugin_format == bfd_plugin_yes + || abfd->plugin_format == bfd_plugin_yes_unused #if BFD_SUPPORTS_PLUGINS || (abfd->plugin_format == bfd_plugin_unknown && bfd_link_plugin_object_p (abfd)) @@ -5694,7 +5695,8 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) && !bfd_link_relocatable (info) && (abfd->flags & BFD_PLUGIN) == 0 && !just_syms - && extsymcount) + && extsymcount != 0 + && is_elf_hash_table (&htab->root)) { int r_sym_shift; @@ -5717,9 +5719,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) if ((s->flags & SEC_RELOC) == 0 || s->reloc_count == 0 || (s->flags & SEC_EXCLUDE) != 0 - || ((info->strip == strip_all - || info->strip == strip_debugger) - && (s->flags & SEC_DEBUGGING) != 0)) + || (s->flags & SEC_DEBUGGING) != 0) continue; internal_relocs = _bfd_elf_link_info_read_relocs @@ -8109,8 +8109,8 @@ _bfd_elf_merge_sections (bfd *obfd, struct bfd_link_info *info) bfd *ibfd; asection *sec; - if (!is_elf_hash_table (info->hash)) - return false; + if (ENABLE_CHECKING && !is_elf_hash_table (info->hash)) + abort (); for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) if ((ibfd->flags & DYNAMIC) == 0 @@ -8133,8 +8133,8 @@ _bfd_elf_merge_sections (bfd *obfd, struct bfd_link_info *info) } if (elf_hash_table (info)->merge_info != NULL) - _bfd_merge_sections (obfd, info, elf_hash_table (info)->merge_info, - merge_sections_remove_hook); + return _bfd_merge_sections (obfd, info, elf_hash_table (info)->merge_info, + merge_sections_remove_hook); return true; } @@ -8819,6 +8819,8 @@ bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2, symp->name = bfd_elf_string_from_elf_section (bfd1, hdr1->sh_link, ssym->st_name); + if (symp->name == NULL) + goto done; symp++; } @@ -8832,6 +8834,8 @@ bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2, symp->name = bfd_elf_string_from_elf_section (bfd2, hdr2->sh_link, ssym->st_name); + if (symp->name == NULL) + goto done; symp++; } @@ -8878,14 +8882,22 @@ bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2, goto done; for (i = 0; i < count1; i++) - symtable1[i].name - = bfd_elf_string_from_elf_section (bfd1, hdr1->sh_link, - symtable1[i].u.isym->st_name); + { + symtable1[i].name + = bfd_elf_string_from_elf_section (bfd1, hdr1->sh_link, + symtable1[i].u.isym->st_name); + if (symtable1[i].name == NULL) + goto done; + } for (i = 0; i < count2; i++) - symtable2[i].name - = bfd_elf_string_from_elf_section (bfd2, hdr2->sh_link, - symtable2[i].u.isym->st_name); + { + symtable2[i].name + = bfd_elf_string_from_elf_section (bfd2, hdr2->sh_link, + symtable2[i].u.isym->st_name); + if (symtable2[i].name == NULL) + goto done; + } /* Sort symbol by name. */ qsort (symtable1, count1, sizeof (struct elf_symbol), @@ -12914,7 +12926,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) { file_ptr off = elf_next_file_pos (abfd); - _bfd_elf_assign_file_position_for_section (symtab_hdr, off, true); + _bfd_elf_assign_file_position_for_section (symtab_hdr, off, true, 0); /* Note that at this point elf_next_file_pos (abfd) is incorrect. We do not yet know the size of the .symtab section. @@ -13358,7 +13370,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) symtab_shndx_hdr->sh_size = amt; off = _bfd_elf_assign_file_position_for_section (symtab_shndx_hdr, - off, true); + off, true, 0); if (bfd_seek (abfd, symtab_shndx_hdr->sh_offset, SEEK_SET) != 0 || (bfd_write (flinfo.symshndxbuf, amt, abfd) != amt)) @@ -13382,7 +13394,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) symstrtab_hdr->sh_addralign = 1; off = _bfd_elf_assign_file_position_for_section (symstrtab_hdr, - off, true); + off, true, 0); elf_next_file_pos (abfd) = off; if (bfd_seek (abfd, symstrtab_hdr->sh_offset, SEEK_SET) != 0 diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c index db6d419..608d179 100644 --- a/bfd/elfnn-loongarch.c +++ b/bfd/elfnn-loongarch.c @@ -84,6 +84,14 @@ struct _bfd_loongarch_elf_obj_tdata && elf_tdata (bfd) != NULL \ && elf_object_id (bfd) == LARCH_ELF_DATA) +static bool +elfNN_loongarch_object (bfd *abfd) +{ + return bfd_elf_allocate_object (abfd, + sizeof (struct _bfd_loongarch_elf_obj_tdata), + LARCH_ELF_DATA); +} + struct relr_entry { asection *sec; @@ -121,6 +129,12 @@ struct loongarch_elf_link_hash_table /* Layout recomputation count. */ bfd_size_type relr_layout_iter; + + /* In BFD DT_RELR is implemented as a "relaxation." If in a relax trip + size_relative_relocs is updating the layout, relax_section may see + a partially updated state (some sections have vma updated but the + others do not), and it's unsafe to do the normal relaxation. */ + bool layout_mutating_for_relr; }; struct loongarch_elf_section_data @@ -157,9 +171,7 @@ loongarch_elf_new_section_hook (bfd *abfd, asection *sec) /* Get the LoongArch ELF linker hash table from a link_info structure. */ #define loongarch_elf_hash_table(p) \ - (elf_hash_table_id (elf_hash_table (p)) == LARCH_ELF_DATA \ - ? ((struct loongarch_elf_link_hash_table *) ((p)->hash)) \ - : NULL) + ((struct loongarch_elf_link_hash_table *) ((p)->hash)) \ #define MINUS_ONE ((bfd_vma) 0 - 1) @@ -844,13 +856,15 @@ loongarch_tls_transition (bfd *input_bfd, } static bool -bad_static_reloc (bfd *abfd, const Elf_Internal_Rela *rel, asection *sec, - unsigned r_type, struct elf_link_hash_entry *h, +bad_static_reloc (struct bfd_link_info *info, + bfd *abfd, const Elf_Internal_Rela *rel, + asection *sec, unsigned r_type, + struct elf_link_hash_entry *h, Elf_Internal_Sym *isym) { - /* We propably can improve the information to tell users that they should - be recompile the code with -fPIC or -fPIE, just like what x86 does. */ reloc_howto_type * r = loongarch_elf_rtype_to_howto (abfd, r_type); + const char *object; + const char *pic; const char *name = NULL; if (h) @@ -862,10 +876,24 @@ bad_static_reloc (bfd *abfd, const Elf_Internal_Rela *rel, asection *sec, if (name == NULL || *name == '\0') name ="<nameless>"; + if (bfd_link_dll (info)) + { + object = _("a shared object"); + pic = _("; recompile with -fPIC"); + } + else + { + if (bfd_link_pie (info)) + object = _("a PIE object"); + else + object = _("a PDE object"); + pic = _("; recompile with -fPIE"); + } + (*_bfd_error_handler) (_("%pB:(%pA+%#lx): relocation %s against `%s` can not be used when making " - "a shared object; recompile with -fPIC"), - abfd, sec, (long) rel->r_offset, r ? r->name : _("<unknown>"), name); + "%s%s"), + abfd, sec, (long) rel->r_offset, r ? r->name : _("<unknown>"), name, object, pic); bfd_set_error (bfd_error_bad_value); return false; } @@ -1035,7 +1063,7 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_LARCH_TLS_LE_HI20_R: case R_LARCH_SOP_PUSH_TLS_TPREL: if (!bfd_link_executable (info)) - return bad_static_reloc (abfd, rel, sec, r_type, h, isym); + return bad_static_reloc (info, abfd, rel, sec, r_type, h, isym); if (!loongarch_elf_record_tls_and_got_reference (abfd, info, h, r_symndx, @@ -1053,7 +1081,7 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_LARCH_ABS_HI20: if (bfd_link_pic (info)) - return bad_static_reloc (abfd, rel, sec, r_type, h, isym); + return bad_static_reloc (info, abfd, rel, sec, r_type, h, isym); /* Fall through. */ case R_LARCH_SOP_PUSH_ABSOLUTE: @@ -1067,6 +1095,18 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, h->non_got_ref = 1; break; + /* Since shared library global symbols interpose, any + PC-relative relocations against external symbols + should not be used to build shared libraries. */ + case R_LARCH_PCREL20_S2: + if (bfd_link_pic (info) + && (sec->flags & SEC_ALLOC) != 0 + && (sec->flags & SEC_READONLY) != 0 + && ! LARCH_REF_LOCAL (info, h)) + return bad_static_reloc (info, abfd, rel, sec, r_type, h, NULL); + + break; + /* For normal cmodel, pcalau12i + addi.d/w used to data. For first version medium cmodel, pcalau12i + jirl are used to function call, it need to creat PLT entry for STT_FUNC and @@ -1084,6 +1124,15 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, h->pointer_equality_needed = 1; } + /* PC-relative relocations are allowed For first version + medium cmodel function call. */ + if (h != NULL && !h->needs_plt + && bfd_link_pic (info) + && (sec->flags & SEC_ALLOC) != 0 + && (sec->flags & SEC_READONLY) != 0 + && ! LARCH_REF_LOCAL (info, h)) + return bad_static_reloc (info, abfd, rel, sec, r_type, h, NULL); + break; case R_LARCH_B16: @@ -2212,6 +2261,8 @@ loongarch_elf_size_relative_relocs (struct bfd_link_info *info, *need_layout = false; } } + + htab->layout_mutating_for_relr = *need_layout; return true; } @@ -3307,7 +3358,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, /* The r_symndx will be STN_UNDEF (zero) only for relocs against symbols from removed linkonce sections, or sections discarded by a linker script. Also for R_*_SOP_PUSH_ABSOLUTE and PCREL to specify const. */ - if (r_symndx == STN_UNDEF || bfd_is_abs_section (sec)) + if (r_symndx == STN_UNDEF) { defined_local = false; resolved_local = false; @@ -3536,7 +3587,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, bfd_reloc_notsupported, is_undefweak, name, "TLS section not be created")); else - relocation -= elf_hash_table (info)->tls_sec->vma; + relocation = tlsoff (info, relocation); } else fatal = (loongarch_reloc_is_fatal @@ -3885,73 +3936,71 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, { Elf_Internal_Rela rela; asection *srel = htab->elf.srelgot; - bfd_vma tls_block_off = 0; - if (LARCH_REF_LOCAL (info, h)) - { - BFD_ASSERT (elf_hash_table (info)->tls_sec); - tls_block_off = relocation - - elf_hash_table (info)->tls_sec->vma; - } + int indx = 0; + bool need_reloc = false; + LARCH_TLS_GD_IE_NEED_DYN_RELOC (info, is_dyn, h, indx, + need_reloc); if (tls_type & GOT_TLS_GD) { - rela.r_offset = sec_addr (got) + got_off; - rela.r_addend = 0; - if (LARCH_REF_LOCAL (info, h)) + if (need_reloc) { - /* Local sym, used in exec, set module id 1. */ - if (bfd_link_executable (info)) - bfd_put_NN (output_bfd, 1, got->contents + got_off); + /* Dynamic resolved Module ID. */ + rela.r_offset = sec_addr (got) + got_off; + rela.r_addend = 0; + rela.r_info = ELFNN_R_INFO (indx, R_LARCH_TLS_DTPMODNN); + bfd_put_NN (output_bfd, 0, got->contents + got_off); + loongarch_elf_append_rela (output_bfd, srel, &rela); + + if (indx == 0) + { + /* Local symbol, tp offset has been known. */ + BFD_ASSERT (! unresolved_reloc); + bfd_put_NN (output_bfd, + tlsoff (info, relocation), + (got->contents + got_off + GOT_ENTRY_SIZE)); + } else { - rela.r_info = ELFNN_R_INFO (0, - R_LARCH_TLS_DTPMODNN); + /* Dynamic resolved block offset. */ + bfd_put_NN (output_bfd, 0, + got->contents + got_off + GOT_ENTRY_SIZE); + rela.r_info = ELFNN_R_INFO (indx, + R_LARCH_TLS_DTPRELNN); + rela.r_offset += GOT_ENTRY_SIZE; loongarch_elf_append_rela (output_bfd, srel, &rela); } - - bfd_put_NN (output_bfd, tls_block_off, - got->contents + got_off + GOT_ENTRY_SIZE); } - /* Dynamic resolved. */ else { - /* Dynamic relocate module id. */ - rela.r_info = ELFNN_R_INFO (h->dynindx, - R_LARCH_TLS_DTPMODNN); - loongarch_elf_append_rela (output_bfd, srel, &rela); - - /* Dynamic relocate offset of block. */ - rela.r_offset += GOT_ENTRY_SIZE; - rela.r_info = ELFNN_R_INFO (h->dynindx, - R_LARCH_TLS_DTPRELNN); - loongarch_elf_append_rela (output_bfd, srel, &rela); + /* In a static link or an executable link with the symbol + binding locally. Mark it as belonging to module 1. */ + bfd_put_NN (output_bfd, 1, got->contents + got_off); + bfd_put_NN (output_bfd, tlsoff (info, relocation), + got->contents + got_off + GOT_ENTRY_SIZE); } } if (tls_type & GOT_TLS_IE) { - rela.r_offset = sec_addr (got) + got_off + ie_off; - if (LARCH_REF_LOCAL (info, h)) + if (need_reloc) { - /* Local sym, used in exec, set module id 1. */ - if (!bfd_link_executable (info)) - { - rela.r_info = ELFNN_R_INFO (0, R_LARCH_TLS_TPRELNN); - rela.r_addend = tls_block_off; - loongarch_elf_append_rela (output_bfd, srel, &rela); - } + bfd_put_NN (output_bfd, 0, + got->contents + got_off + ie_off); + rela.r_offset = sec_addr (got) + got_off + ie_off; + rela.r_addend = 0; - bfd_put_NN (output_bfd, tls_block_off, - got->contents + got_off + ie_off); + if (indx == 0) + rela.r_addend = tlsoff (info, relocation); + rela.r_info = ELFNN_R_INFO (indx, R_LARCH_TLS_TPRELNN); + loongarch_elf_append_rela (output_bfd, srel, &rela); } - /* Dynamic resolved. */ else { - /* Dynamic relocate offset of block. */ - rela.r_info = ELFNN_R_INFO (h->dynindx, - R_LARCH_TLS_TPRELNN); - rela.r_addend = 0; - loongarch_elf_append_rela (output_bfd, srel, &rela); + /* In a static link or an executable link with the symbol + binding locally, compute offset directly. */ + bfd_put_NN (output_bfd, tlsoff (info, relocation), + got->contents + got_off + ie_off); } } } @@ -4061,7 +4110,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, /* For 2G jump, generate pcalau12i, jirl. */ /* If use jirl, turns to R_LARCH_B16. */ uint32_t insn = bfd_get (32, input_bfd, contents + rel->r_offset); - if ((insn & 0x4c000000) == 0x4c000000) + if (LARCH_INSN_JIRL (insn)) { relocation &= 0xfff; /* Signed extend. */ @@ -4132,8 +4181,10 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (is_dyn, bfd_link_pic (info), h) + && !bfd_is_abs_section(h->root.u.def.section) && bfd_link_pic (info) - && LARCH_REF_LOCAL (info, h)) + && LARCH_REF_LOCAL (info, h) + && !info->enable_dt_relr) { Elf_Internal_Rela rela; rela.r_offset = sec_addr (got) + got_off; @@ -4153,7 +4204,8 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, && local_got_offsets[r_symndx] != MINUS_ONE); got_off = local_got_offsets[r_symndx] & (~(bfd_vma)1); - if ((local_got_offsets[r_symndx] & 1) == 0) + if (sym->st_shndx != SHN_ABS + && (local_got_offsets[r_symndx] & 1) == 0) { if (bfd_link_pic (info) && !info->enable_dt_relr) { @@ -4700,7 +4752,7 @@ loongarch_tls_perform_trans (bfd *abfd, asection *sec, pcalalau12i $a0,%desc_pc_hi20(var) => lu12i.w $a0,%le_hi20(var) */ - bfd_put (32, abfd, LARCH_LU12I_W | LARCH_RD_A0, + bfd_put (32, abfd, LARCH_OP_LU12I_W | LARCH_RD_A0, contents + rel->r_offset); rel->r_info = ELFNN_R_INFO (r_symndx, R_LARCH_TLS_LE_HI20); } @@ -4721,8 +4773,8 @@ loongarch_tls_perform_trans (bfd *abfd, asection *sec, addi.d $a0,$a0,%desc_pc_lo12(var) => ori $a0,$a0,le_lo12(var) */ - insn = LARCH_ORI | LARCH_RD_RJ_A0; - bfd_put (32, abfd, LARCH_ORI | LARCH_RD_RJ_A0, + insn = LARCH_OP_ORI | LARCH_RD_RJ_A0; + bfd_put (32, abfd, LARCH_OP_ORI | LARCH_RD_RJ_A0, contents + rel->r_offset); rel->r_info = ELFNN_R_INFO (r_symndx, R_LARCH_TLS_LE_LO12); } @@ -4732,7 +4784,7 @@ loongarch_tls_perform_trans (bfd *abfd, asection *sec, addi.d $a0,$a0,%desc_pc_lo12(var) => ld.d $a0,$a0,%ie_pc_lo12(var) */ - bfd_put (32, abfd, LARCH_LD_D | LARCH_RD_RJ_A0, + bfd_put (32, abfd, LARCH_OP_LD_D | LARCH_RD_RJ_A0, contents + rel->r_offset); rel->r_info = ELFNN_R_INFO (r_symndx, R_LARCH_TLS_IE_PC_LO12); } @@ -4759,7 +4811,7 @@ loongarch_tls_perform_trans (bfd *abfd, asection *sec, lu12i.w $rd,%le_hi20(var) */ insn = bfd_getl32 (contents + rel->r_offset); - bfd_put (32, abfd, LARCH_LU12I_W | (insn & 0x1f), + bfd_put (32, abfd, LARCH_OP_LU12I_W | LARCH_GET_RD(insn), contents + rel->r_offset); rel->r_info = ELFNN_R_INFO (r_symndx, R_LARCH_TLS_LE_HI20); } @@ -4773,7 +4825,7 @@ loongarch_tls_perform_trans (bfd *abfd, asection *sec, ori $rd,$rj,le_lo12(var) */ insn = bfd_getl32 (contents + rel->r_offset); - bfd_put (32, abfd, LARCH_ORI | (insn & 0x3ff), + bfd_put (32, abfd, LARCH_OP_ORI | (insn & 0x3ff), contents + rel->r_offset); rel->r_info = ELFNN_R_INFO (r_symndx, R_LARCH_TLS_LE_LO12); } @@ -4838,9 +4890,11 @@ loongarch_tls_perform_trans (bfd *abfd, asection *sec, */ static bool loongarch_relax_tls_le (bfd *abfd, asection *sec, - Elf_Internal_Rela *rel, + asection *sym_sec ATTRIBUTE_UNUSED, + Elf_Internal_Rela *rel, bfd_vma symval, struct bfd_link_info *link_info, - bfd_vma symval) + bool *agin ATTRIBUTE_UNUSED, + bfd_vma max_alignment ATTRIBUTE_UNUSED) { bfd_byte *contents = elf_section_data (sec)->this_hdr.contents; uint32_t insn = bfd_get (32, abfd, contents + rel->r_offset); @@ -4848,7 +4902,7 @@ loongarch_relax_tls_le (bfd *abfd, asection *sec, symval = symval - elf_hash_table (link_info)->tls_sec->vma; /* The old LE instruction sequence can be relaxed when the symbol offset is smaller than the 12-bit range. */ - if (ELFNN_R_TYPE ((rel + 1)->r_info) == R_LARCH_RELAX && (symval <= 0xfff)) + if (symval <= 0xfff) { switch (ELFNN_R_TYPE (rel->r_info)) { @@ -4871,11 +4925,11 @@ loongarch_relax_tls_le (bfd *abfd, asection *sec, /* Change rj to $tp. */ insn_rj = 0x2 << 5; /* Get rd register. */ - insn_rd = insn & 0x1f; + insn_rd = LARCH_GET_RD (insn); /* Write symbol offset. */ symval <<= 10; /* Writes the modified instruction. */ - insn = insn & 0xffc00000; + insn = insn & LARCH_MK_ADDI_D; insn = insn | symval | insn_rj | insn_rd; bfd_put (32, abfd, insn, contents + rel->r_offset); } @@ -4890,7 +4944,7 @@ loongarch_relax_tls_le (bfd *abfd, asection *sec, break; case R_LARCH_TLS_LE_LO12: - bfd_put (32, abfd, LARCH_ORI | (insn & 0x1f), + bfd_put (32, abfd, LARCH_OP_ORI | LARCH_GET_RD (insn), contents + rel->r_offset); break; @@ -4936,7 +4990,7 @@ loongarch_relax_pcala_addi (bfd *abfd, asection *sec, asection *sym_sec, Elf_Internal_Rela *rel_lo = rel_hi + 2; uint32_t pca = bfd_get (32, abfd, contents + rel_hi->r_offset); uint32_t add = bfd_get (32, abfd, contents + rel_lo->r_offset); - uint32_t rd = pca & 0x1f; + uint32_t rd = LARCH_GET_RD (pca); /* This section's output_offset need to subtract the bytes of instructions relaxed by the previous sections, so it needs to be updated beforehand. @@ -4957,18 +5011,14 @@ loongarch_relax_pcala_addi (bfd *abfd, asection *sec, asection *sym_sec, else if (symval < pc) pc += (max_alignment > 4 ? max_alignment : 0); - const uint32_t addi_d = 0x02c00000; - const uint32_t pcaddi = 0x18000000; + const uint32_t pcaddi = LARCH_OP_PCADDI; /* Is pcalau12i + addi.d insns? */ if ((ELFNN_R_TYPE (rel_lo->r_info) != R_LARCH_PCALA_LO12) - || (ELFNN_R_TYPE ((rel_lo + 1)->r_info) != R_LARCH_RELAX) - || (ELFNN_R_TYPE ((rel_hi + 1)->r_info) != R_LARCH_RELAX) - || (rel_hi->r_offset + 4 != rel_lo->r_offset) - || ((add & addi_d) != addi_d) + || !LARCH_INSN_ADDI_D (add) /* Is pcalau12i $rd + addi.d $rd,$rd? */ - || ((add & 0x1f) != rd) - || (((add >> 5) & 0x1f) != rd) + || (LARCH_GET_RD (add) != rd) + || (LARCH_GET_RJ (add) != rd) /* Can be relaxed to pcaddi? */ || (symval & 0x3) /* 4 bytes align. */ || ((bfd_signed_vma)(symval - pc) < (bfd_signed_vma)(int32_t)0xffe00000) @@ -5001,7 +5051,7 @@ loongarch_relax_call36 (bfd *abfd, asection *sec, asection *sym_sec, { bfd_byte *contents = elf_section_data (sec)->this_hdr.contents; uint32_t jirl = bfd_get (32, abfd, contents + rel->r_offset + 4); - uint32_t rd = jirl & 0x1f; + uint32_t rd = LARCH_GET_RD (jirl); /* This section's output_offset need to subtract the bytes of instructions relaxed by the previous sections, so it needs to be updated beforehand. @@ -5022,11 +5072,8 @@ loongarch_relax_call36 (bfd *abfd, asection *sec, asection *sym_sec, else if (symval < pc) pc += (max_alignment > 4 ? max_alignment : 0); - const uint32_t jirl_opcode = 0x4c000000; - /* Is pcalau12i + addi.d insns? */ - if ((ELFNN_R_TYPE ((rel + 1)->r_info) != R_LARCH_RELAX) - || ((jirl & jirl_opcode) != jirl_opcode) + if (!LARCH_INSN_JIRL (jirl) || ((bfd_signed_vma)(symval - pc) < (bfd_signed_vma)(int32_t)0xf8000000) || ((bfd_signed_vma)(symval - pc) > (bfd_signed_vma)(int32_t)0x7fffffc)) return false; @@ -5034,8 +5081,8 @@ loongarch_relax_call36 (bfd *abfd, asection *sec, asection *sym_sec, /* Continue next relax trip. */ *again = true; - const uint32_t bl = 0x54000000; - const uint32_t b = 0x50000000; + const uint32_t bl = LARCH_OP_BL; + const uint32_t b = LARCH_OP_B; if (rd) bfd_put (32, abfd, bl, contents + rel->r_offset); @@ -5052,23 +5099,24 @@ loongarch_relax_call36 (bfd *abfd, asection *sec, asection *sym_sec, /* Relax pcalau12i,ld.d => pcalau12i,addi.d. */ static bool loongarch_relax_pcala_ld (bfd *abfd, asection *sec, - Elf_Internal_Rela *rel_hi) + asection *sym_sec ATTRIBUTE_UNUSED, + Elf_Internal_Rela *rel_hi, + bfd_vma symval ATTRIBUTE_UNUSED, + struct bfd_link_info *info ATTRIBUTE_UNUSED, + bool *again ATTRIBUTE_UNUSED, + bfd_vma max_alignment ATTRIBUTE_UNUSED) { bfd_byte *contents = elf_section_data (sec)->this_hdr.contents; Elf_Internal_Rela *rel_lo = rel_hi + 2; uint32_t pca = bfd_get (32, abfd, contents + rel_hi->r_offset); uint32_t ld = bfd_get (32, abfd, contents + rel_lo->r_offset); - uint32_t rd = pca & 0x1f; - const uint32_t ld_d = 0x28c00000; - uint32_t addi_d = 0x02c00000; + uint32_t rd = LARCH_GET_RD (pca); + uint32_t addi_d = LARCH_OP_ADDI_D; if ((ELFNN_R_TYPE (rel_lo->r_info) != R_LARCH_GOT_PC_LO12) - || (ELFNN_R_TYPE ((rel_lo + 1)->r_info) != R_LARCH_RELAX) - || (ELFNN_R_TYPE ((rel_hi + 1)->r_info) != R_LARCH_RELAX) - || (rel_hi->r_offset + 4 != rel_lo->r_offset) - || ((ld & 0x1f) != rd) - || (((ld >> 5) & 0x1f) != rd) - || ((ld & ld_d) != ld_d)) + || (LARCH_GET_RD (ld) != rd) + || (LARCH_GET_RJ (ld) != rd) + || !LARCH_INSN_LD_D (ld)) return false; addi_d = addi_d | (rd << 5) | rd; @@ -5095,11 +5143,12 @@ bfd_elfNN_loongarch_set_data_segment_info (struct bfd_link_info *info, /* Implement R_LARCH_ALIGN by deleting excess alignment NOPs. Once we've handled an R_LARCH_ALIGN, we can't relax anything else. */ static bool -loongarch_relax_align (bfd *abfd, asection *sec, - asection *sym_sec, - struct bfd_link_info *link_info, +loongarch_relax_align (bfd *abfd, asection *sec, asection *sym_sec, Elf_Internal_Rela *rel, - bfd_vma symval) + bfd_vma symval ATTRIBUTE_UNUSED, + struct bfd_link_info *link_info, + bool *again ATTRIBUTE_UNUSED, + bfd_vma max_alignment ATTRIBUTE_UNUSED) { bfd_vma addend, max = 0, alignment = 1; @@ -5161,7 +5210,7 @@ loongarch_relax_tls_ld_gd_desc (bfd *abfd, asection *sec, asection *sym_sec, Elf_Internal_Rela *rel_lo = rel_hi + 2; uint32_t pca = bfd_get (32, abfd, contents + rel_hi->r_offset); uint32_t add = bfd_get (32, abfd, contents + rel_lo->r_offset); - uint32_t rd = pca & 0x1f; + uint32_t rd = LARCH_GET_RD (pca); /* This section's output_offset need to subtract the bytes of instructions relaxed by the previous sections, so it needs to be updated beforehand. @@ -5182,19 +5231,15 @@ loongarch_relax_tls_ld_gd_desc (bfd *abfd, asection *sec, asection *sym_sec, else if (symval < pc) pc += (max_alignment > 4 ? max_alignment : 0); - const uint32_t addi_d = 0x02c00000; - const uint32_t pcaddi = 0x18000000; + const uint32_t pcaddi = LARCH_OP_PCADDI; /* Is pcalau12i + addi.d insns? */ if ((ELFNN_R_TYPE (rel_lo->r_info) != R_LARCH_GOT_PC_LO12 && ELFNN_R_TYPE (rel_lo->r_info) != R_LARCH_TLS_DESC_PC_LO12) - || (ELFNN_R_TYPE ((rel_lo + 1)->r_info) != R_LARCH_RELAX) - || (ELFNN_R_TYPE ((rel_hi + 1)->r_info) != R_LARCH_RELAX) - || (rel_hi->r_offset + 4 != rel_lo->r_offset) - || ((add & addi_d) != addi_d) + || !LARCH_INSN_ADDI_D (add) /* Is pcalau12i $rd + addi.d $rd,$rd? */ - || ((add & 0x1f) != rd) - || (((add >> 5) & 0x1f) != rd) + || (LARCH_GET_RD (add) != rd) + || (LARCH_GET_RJ (add) != rd) /* Can be relaxed to pcaddi? */ || (symval & 0x3) /* 4 bytes align. */ || ((bfd_signed_vma)(symval - pc) < (bfd_signed_vma)(int32_t)0xffe00000) @@ -5247,39 +5292,57 @@ loongarch_get_max_alignment (asection *sec) return (bfd_vma) 1 << max_alignment_power; } +typedef bool (*relax_func_t) (bfd *, asection *, asection *, + Elf_Internal_Rela *, bfd_vma, + struct bfd_link_info *, bool *, + bfd_vma); + static bool loongarch_elf_relax_section (bfd *abfd, asection *sec, - struct bfd_link_info *info, - bool *again) + struct bfd_link_info *info, + bool *again) { - struct loongarch_elf_link_hash_table *htab = loongarch_elf_hash_table (info); - struct bfd_elf_section_data *data = elf_section_data (sec); - Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (abfd); - Elf_Internal_Rela *relocs; *again = false; - bfd_vma max_alignment = 0; + + if (!is_elf_hash_table (info->hash) + || elf_hash_table_id (elf_hash_table (info)) != LARCH_ELF_DATA) + return true; + + struct loongarch_elf_link_hash_table *htab = loongarch_elf_hash_table (info); + + /* It may happen that some sections have updated vma but the others do + not. Go to the next relax trip (size_relative_relocs should have + been demending another relax trip anyway). */ + if (htab->layout_mutating_for_relr) + return true; if (bfd_link_relocatable (info) || sec->sec_flg0 - || (sec->flags & SEC_RELOC) == 0 || sec->reloc_count == 0 + || (sec->flags & SEC_RELOC) == 0 + || (sec->flags & SEC_HAS_CONTENTS) == 0 + /* The exp_seg_relro_adjust is enum phase_enum (0x4). */ + || *(htab->data_segment_phase) == 4 || (info->disable_target_specific_optimizations - && info->relax_pass == 0) - /* The exp_seg_relro_adjust is enum phase_enum (0x4), - and defined in ld/ldexp.h. */ - || *(htab->data_segment_phase) == 4) + && info->relax_pass == 0)) return true; + struct bfd_elf_section_data *data = elf_section_data (sec); + Elf_Internal_Rela *relocs; if (data->relocs) relocs = data->relocs; else if (!(relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, info->keep_memory))) return true; + data->relocs = relocs; + /* Read this BFD's contents if we haven't done so already. */ if (!data->this_hdr.contents && !bfd_malloc_and_get_section (abfd, sec, &data->this_hdr.contents)) return true; + /* Read this BFD's symbols if we haven't done so already. */ + Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (abfd); if (symtab_hdr->sh_info != 0 && !symtab_hdr->contents && !(symtab_hdr->contents = @@ -5288,11 +5351,9 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec, 0, NULL, NULL, NULL))) return true; - data->relocs = relocs; - /* Estimate the maximum alignment for all output sections once time should be enough. */ - max_alignment = htab->max_alignment; + bfd_vma max_alignment = htab->max_alignment; if (max_alignment == (bfd_vma) -1) { max_alignment = loongarch_get_max_alignment (sec); @@ -5310,6 +5371,93 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec, unsigned long r_type = ELFNN_R_TYPE (rel->r_info); unsigned long r_symndx = ELFNN_R_SYM (rel->r_info); + if (r_symndx >= symtab_hdr->sh_info) + { + h = elf_sym_hashes (abfd)[r_symndx - symtab_hdr->sh_info]; + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + } + + /* If the conditions for tls type transition are met, type + transition is performed instead of relax. + During the transition from DESC->IE/LE, there are 2 situations + depending on the different configurations of the relax/norelax + option. + If the -relax option is used, the extra nops will be removed, + and this transition is performed in pass 0. + If the --no-relax option is used, nop will be retained, and + this transition is performed in pass 1. */ + if (IS_LOONGARCH_TLS_TRANS_RELOC (r_type) + && (i + 1 != sec->reloc_count) + && ELFNN_R_TYPE (rel[1].r_info) == R_LARCH_RELAX + && rel->r_offset == rel[1].r_offset + && loongarch_can_trans_tls (abfd, info, h, r_symndx, r_type)) + { + loongarch_tls_perform_trans (abfd, sec, rel, h, info); + r_type = ELFNN_R_TYPE (rel->r_info); + } + + relax_func_t relax_func = NULL; + if (info->relax_pass == 0) + { + switch (r_type) + { + case R_LARCH_PCALA_HI20: + relax_func = loongarch_relax_pcala_addi; + break; + case R_LARCH_GOT_PC_HI20: + relax_func = loongarch_relax_pcala_ld; + break; + case R_LARCH_CALL36: + relax_func = loongarch_relax_call36; + break; + case R_LARCH_TLS_LE_HI20_R: + case R_LARCH_TLS_LE_LO12_R: + case R_LARCH_TLS_LE_ADD_R: + case R_LARCH_TLS_LE_HI20: + case R_LARCH_TLS_LE_LO12: + case R_LARCH_TLS_LE64_LO20: + case R_LARCH_TLS_LE64_HI12: + relax_func = loongarch_relax_tls_le; + break; + case R_LARCH_TLS_LD_PC_HI20: + case R_LARCH_TLS_GD_PC_HI20: + case R_LARCH_TLS_DESC_PC_HI20: + relax_func = loongarch_relax_tls_ld_gd_desc; + break; + default: + continue; + } + + /* Only relax this reloc if it is paired with R_RISCV_RELAX. */ + if (r_type == R_LARCH_TLS_LD_PC_HI20 + || r_type == R_LARCH_TLS_GD_PC_HI20 + || r_type == R_LARCH_TLS_DESC_PC_HI20 + || r_type == R_LARCH_PCALA_HI20 + || r_type == R_LARCH_GOT_PC_HI20) + { + if ((i + 2) == sec->reloc_count - 1 + || ELFNN_R_TYPE ((rel + 1)->r_info) != R_LARCH_RELAX + || ELFNN_R_TYPE ((rel + 3)->r_info) != R_LARCH_RELAX + || rel->r_offset != (rel + 1)->r_offset + || (rel + 2)->r_offset != (rel + 3)->r_offset + || rel->r_offset + 4 != (rel + 2)->r_offset) + continue; + } + else + { + if (i == sec->reloc_count - 1 + || ELFNN_R_TYPE ((rel + 1)->r_info) != R_LARCH_RELAX + || rel->r_offset != (rel + 1)->r_offset) + continue; + } + } + else if (info->relax_pass == 1 && r_type == R_LARCH_ALIGN) + relax_func = loongarch_relax_align; + else + continue; + /* Four kind of relocations: Normal: symval is the symbol address. R_LARCH_ALIGN: symval is the address of the last NOP instruction @@ -5322,29 +5470,28 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec, { Elf_Internal_Sym *sym = (Elf_Internal_Sym *)symtab_hdr->contents + r_symndx; - if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC) + + if ((ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC + && r_type != R_LARCH_CALL36) + || sym->st_shndx == SHN_ABS) continue; /* Only TLS instruction sequences that are accompanied by R_LARCH_RELAX and cannot perform type transition can be relaxed. */ - if (R_LARCH_TLS_LD_PC_HI20 == r_type - || R_LARCH_TLS_GD_PC_HI20 == r_type - || (R_LARCH_TLS_DESC_PC_HI20 == r_type - && (i + 1 != sec->reloc_count) - && ELFNN_R_TYPE (rel[1].r_info) == R_LARCH_RELAX - && ! loongarch_can_trans_tls (abfd, info, h, - r_symndx, r_type))) + if (r_type == R_LARCH_TLS_LD_PC_HI20 + || r_type == R_LARCH_TLS_GD_PC_HI20 + || r_type == R_LARCH_TLS_DESC_PC_HI20) { sym_sec = htab->elf.sgot; symval = elf_local_got_offsets (abfd)[r_symndx]; char tls_type = _bfd_loongarch_elf_tls_type (abfd, h, r_symndx); - if (R_LARCH_TLS_DESC_PC_HI20 == r_type + if (r_type == R_LARCH_TLS_DESC_PC_HI20 && GOT_TLS_GD_BOTH_P (tls_type)) symval += 2 * GOT_ENTRY_SIZE; } - else if (sym->st_shndx == SHN_UNDEF || R_LARCH_ALIGN == r_type) + else if (sym->st_shndx == SHN_UNDEF || r_type == R_LARCH_ALIGN) { sym_sec = sec; symval = rel->r_offset; @@ -5358,42 +5505,47 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec, } else { - r_symndx = ELFNN_R_SYM (rel->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[r_symndx]; - - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - - /* Disable the relaxation for ifunc. */ - if (h != NULL && h->type == STT_GNU_IFUNC) + if (h != NULL + && ((h->type == STT_GNU_IFUNC + && r_type != R_LARCH_CALL36) + || bfd_is_abs_section (h->root.u.def.section))) continue; /* The GOT entry of tls symbols must in current execute file or shared object. */ - if (R_LARCH_TLS_LD_PC_HI20 == r_type - || R_LARCH_TLS_GD_PC_HI20 == r_type - || (R_LARCH_TLS_DESC_PC_HI20 == r_type - && (i + 1 != sec->reloc_count) - && ELFNN_R_TYPE (rel[1].r_info) == R_LARCH_RELAX - && !loongarch_can_trans_tls (abfd, info, h, - r_symndx, r_type))) + if (r_type == R_LARCH_TLS_LD_PC_HI20 + || r_type == R_LARCH_TLS_GD_PC_HI20 + || r_type == R_LARCH_TLS_DESC_PC_HI20) { sym_sec = htab->elf.sgot; symval = h->got.offset; char tls_type = _bfd_loongarch_elf_tls_type (abfd, h, r_symndx); - if (R_LARCH_TLS_DESC_PC_HI20 == r_type + if (r_type == R_LARCH_TLS_DESC_PC_HI20 && GOT_TLS_GD_BOTH_P (tls_type)) symval += 2 * GOT_ENTRY_SIZE; } + else if (h->plt.offset != MINUS_ONE) + { + sym_sec = htab->elf.splt ? htab->elf.splt : htab->elf.iplt; + symval = h->plt.offset; + } + /* Like loongarch_elf_relocate_section, set relocation(offset) to 0. + Undefweak for other relocations handing in the future. */ + else if (h->root.type == bfd_link_hash_undefweak + && !h->root.linker_def + && r_type == R_LARCH_CALL36) + { + sym_sec = sec; + symval = rel->r_offset; + } else if ((h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak) && h->root.u.def.section != NULL && h->root.u.def.section->output_section != NULL) { - symval = h->root.u.def.value; sym_sec = h->root.u.def.section; + symval = h->root.u.def.value; } else continue; @@ -5420,7 +5572,7 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec, + (alingmeng - 4). If r_symndx is 0, alignmeng-4 is r_addend. If r_symndx > 0, alignment-4 is 2^(r_addend & 0xff)-4. */ - else if (R_LARCH_ALIGN == r_type) + else if (r_type == R_LARCH_ALIGN) if (r_symndx > 0) symval += ((1 << (rel->r_addend & 0xff)) - 4); else @@ -5430,82 +5582,14 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec, symval += sec_addr (sym_sec); - /* If the conditions for tls type transition are met, type - transition is performed instead of relax. - During the transition from DESC->IE/LE, there are 2 situations - depending on the different configurations of the relax/norelax - option. - If the -relax option is used, the extra nops will be removed, - and this transition is performed in pass 0. - If the --no-relax option is used, nop will be retained, and - this transition is performed in pass 1. */ - if (IS_LOONGARCH_TLS_TRANS_RELOC (r_type) - && (i + 1 != sec->reloc_count) - && ELFNN_R_TYPE (rel[1].r_info) == R_LARCH_RELAX - && loongarch_can_trans_tls (abfd, info, h, r_symndx, r_type)) - { - loongarch_tls_perform_trans (abfd, sec, rel, h, info); - r_type = ELFNN_R_TYPE (rel->r_info); - } - - switch (r_type) - { - case R_LARCH_ALIGN: - if (1 == info->relax_pass) - loongarch_relax_align (abfd, sec, sym_sec, info, rel, symval); - break; + if (r_type == R_LARCH_GOT_PC_HI20 && !local_got) + continue; - case R_LARCH_DELETE: - if (1 == info->relax_pass) - { - loongarch_relax_delete_bytes (abfd, sec, rel->r_offset, 4, info); - rel->r_info = ELFNN_R_INFO (0, R_LARCH_NONE); - } - break; - case R_LARCH_CALL36: - if (0 == info->relax_pass && (i + 2) <= sec->reloc_count) - loongarch_relax_call36 (abfd, sec, sym_sec, rel, symval, + if (relax_func (abfd, sec, sym_sec, rel, symval, + info, again, max_alignment) + && relax_func == loongarch_relax_pcala_ld) + loongarch_relax_pcala_addi (abfd, sec, sym_sec, rel, symval, info, again, max_alignment); - break; - - case R_LARCH_TLS_LE_HI20_R: - case R_LARCH_TLS_LE_LO12_R: - case R_LARCH_TLS_LE_ADD_R: - case R_LARCH_TLS_LE_HI20: - case R_LARCH_TLS_LE_LO12: - case R_LARCH_TLS_LE64_LO20: - case R_LARCH_TLS_LE64_HI12: - if (0 == info->relax_pass && (i + 2) <= sec->reloc_count) - loongarch_relax_tls_le (abfd, sec, rel, info, symval); - break; - - case R_LARCH_PCALA_HI20: - if (0 == info->relax_pass && (i + 4) <= sec->reloc_count) - loongarch_relax_pcala_addi (abfd, sec, sym_sec, rel, symval, - info, again, max_alignment); - break; - - case R_LARCH_GOT_PC_HI20: - if (local_got && 0 == info->relax_pass - && (i + 4) <= sec->reloc_count) - { - if (loongarch_relax_pcala_ld (abfd, sec, rel)) - loongarch_relax_pcala_addi (abfd, sec, sym_sec, rel, symval, - info, again, max_alignment); - } - break; - - case R_LARCH_TLS_LD_PC_HI20: - case R_LARCH_TLS_GD_PC_HI20: - case R_LARCH_TLS_DESC_PC_HI20: - if (0 == info->relax_pass && (i + 4) <= sec->reloc_count) - loongarch_relax_tls_ld_gd_desc (abfd, sec, sym_sec, rel, symval, - info, again, max_alignment); - break; - - default: - break; - } } return true; @@ -6132,6 +6216,8 @@ elf_loongarch64_hash_symbol (struct elf_link_hash_entry *h) #define bfd_elfNN_bfd_reloc_name_lookup loongarch_reloc_name_lookup #define elf_info_to_howto_rel NULL /* Fall through to elf_info_to_howto. */ #define elf_info_to_howto loongarch_info_to_howto_rela +#define bfd_elfNN_mkobject \ + elfNN_loongarch_object #define bfd_elfNN_bfd_merge_private_bfd_data \ elfNN_loongarch_merge_private_bfd_data diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c index 90ecc27..c8bf45f 100644 --- a/bfd/elfnn-riscv.c +++ b/bfd/elfnn-riscv.c @@ -5612,7 +5612,7 @@ riscv_elf_is_target_special_symbol (bfd *abfd, asymbol *sym) { /* PR27584, local and empty symbols. Since they are usually generated for pcrel relocations. */ - return (!strcmp (sym->name, "") + return (!sym->name[0] || _bfd_elf_is_local_label_name (abfd, sym->name) /* PR27916, mapping symbols. */ || riscv_elf_is_mapping_symbols (sym->name)); diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c index b8f314d..4b48d8e 100644 --- a/bfd/elfxx-riscv.c +++ b/bfd/elfxx-riscv.c @@ -1182,8 +1182,8 @@ static struct riscv_implicit_subset riscv_implicit_subsets[] = {"m", "+zmmul", check_implicit_always}, - {"zabha", "+a", check_implicit_always}, - {"zacas", "+a", check_implicit_always}, + {"zabha", "+zaamo", check_implicit_always}, + {"zacas", "+zaamo", check_implicit_always}, {"a", "+zaamo,+zalrsc", check_implicit_always}, {"xsfvcp", "+zve32x", check_implicit_always}, @@ -1213,6 +1213,7 @@ static struct riscv_implicit_subset riscv_implicit_subsets[] = {"zcd", "+d,+zca", check_implicit_always}, {"zcf", "+f,+zca", check_implicit_always}, {"zcmp", "+zca", check_implicit_always}, + {"zcmop", "+zca", check_implicit_always}, {"shcounterenw", "+h", check_implicit_always}, {"shgatpa", "+h", check_implicit_always}, @@ -1344,6 +1345,7 @@ static struct riscv_supported_ext riscv_supported_std_z_ext[] = {"zihintntl", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, {"zihintpause", ISA_SPEC_CLASS_DRAFT, 2, 0, 0 }, {"zihpm", ISA_SPEC_CLASS_DRAFT, 2, 0, 0 }, + {"zimop", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, {"zmmul", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, {"za64rs", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, {"za128rs", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, @@ -1420,6 +1422,7 @@ static struct riscv_supported_ext riscv_supported_std_z_ext[] = {"zcb", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, {"zcf", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, {"zcd", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, + {"zcmop", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, {"zcmp", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, {NULL, 0, 0, 0, 0} }; @@ -1436,6 +1439,7 @@ static struct riscv_supported_ext riscv_supported_std_s_ext[] = {"smcsrind", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, {"smcntrpmf", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, {"smepmp", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, + {"smrnmi", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, {"smstateen", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, {"ssaia", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, {"ssccptr", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, @@ -1463,11 +1467,13 @@ static struct riscv_supported_ext riscv_supported_std_zxm_ext[] = static struct riscv_supported_ext riscv_supported_vendor_x_ext[] = { - {"xcvmac", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, {"xcvalu", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, - {"xcvelw", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, {"xcvbi", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, + {"xcvbitmanip", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, + {"xcvelw", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, + {"xcvmac", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, {"xcvmem", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, + {"xcvsimd", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, {"xtheadba", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, {"xtheadbb", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, {"xtheadbs", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, @@ -2556,6 +2562,8 @@ riscv_multi_subset_supports (riscv_parse_subset_t *rps, || riscv_subset_supports (rps, "zca"))); case INSN_CLASS_ZIHINTPAUSE: return riscv_subset_supports (rps, "zihintpause"); + case INSN_CLASS_ZIMOP: + return riscv_subset_supports (rps, "zimop"); case INSN_CLASS_M: return riscv_subset_supports (rps, "m"); case INSN_CLASS_ZMMUL: @@ -2708,22 +2716,28 @@ riscv_multi_subset_supports (riscv_parse_subset_t *rps, case INSN_CLASS_ZCB_AND_ZMMUL: return (riscv_subset_supports (rps, "zcb") && riscv_subset_supports (rps, "zmmul")); + case INSN_CLASS_ZCMOP: + return riscv_subset_supports (rps, "zcmop"); case INSN_CLASS_ZCMP: return riscv_subset_supports (rps, "zcmp"); case INSN_CLASS_SVINVAL: return riscv_subset_supports (rps, "svinval"); case INSN_CLASS_H: return riscv_subset_supports (rps, "h"); - case INSN_CLASS_XCVMAC: - return riscv_subset_supports (rps, "xcvmac"); case INSN_CLASS_XCVALU: return riscv_subset_supports (rps, "xcvalu"); - case INSN_CLASS_XCVELW: - return riscv_subset_supports (rps, "xcvelw"); case INSN_CLASS_XCVBI: return riscv_subset_supports (rps, "xcvbi"); + case INSN_CLASS_XCVBITMANIP: + return riscv_subset_supports (rps, "xcvbitmanip"); + case INSN_CLASS_XCVELW: + return riscv_subset_supports (rps, "xcvelw"); + case INSN_CLASS_XCVMAC: + return riscv_subset_supports (rps, "xcvmac"); case INSN_CLASS_XCVMEM: return riscv_subset_supports (rps, "xcvmem"); + case INSN_CLASS_XCVSIMD: + return riscv_subset_supports (rps, "xcvsimd"); case INSN_CLASS_XTHEADBA: return riscv_subset_supports (rps, "xtheadba"); case INSN_CLASS_XTHEADBB: @@ -2803,6 +2817,8 @@ riscv_multi_subset_supports_ext (riscv_parse_subset_t *rps, return _("c' or `zca"); case INSN_CLASS_ZIHINTPAUSE: return "zihintpause"; + case INSN_CLASS_ZIMOP: + return "zimop"; case INSN_CLASS_M: return "m"; case INSN_CLASS_ZMMUL: @@ -2982,22 +2998,28 @@ riscv_multi_subset_supports_ext (riscv_parse_subset_t *rps, return _("zcb' and `zbb"); case INSN_CLASS_ZCB_AND_ZMMUL: return _("zcb' and `zmmul', or `zcb' and `m"); + case INSN_CLASS_ZCMOP: + return "zcmop"; case INSN_CLASS_ZCMP: return "zcmp"; case INSN_CLASS_SVINVAL: return "svinval"; case INSN_CLASS_H: return _("h"); - case INSN_CLASS_XCVMAC: - return "xcvmac"; case INSN_CLASS_XCVALU: return "xcvalu"; - case INSN_CLASS_XCVELW: - return "xcvelw"; case INSN_CLASS_XCVBI: return "xcvbi"; + case INSN_CLASS_XCVBITMANIP: + return "xcvbitmanip"; + case INSN_CLASS_XCVELW: + return "xcvelw"; + case INSN_CLASS_XCVMAC: + return "xcvmac"; case INSN_CLASS_XCVMEM: return "xcvmem"; + case INSN_CLASS_XCVSIMD: + return "xcvsimd"; case INSN_CLASS_XTHEADBA: return "xtheadba"; case INSN_CLASS_XTHEADBB: diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h index 075f1bd..d10391d 100644 --- a/bfd/elfxx-target.h +++ b/bfd/elfxx-target.h @@ -187,11 +187,6 @@ #define bfd_elfNN_bfd_gc_sections bfd_elf_gc_sections #endif -#ifndef bfd_elfNN_bfd_merge_sections -#define bfd_elfNN_bfd_merge_sections \ - _bfd_elf_merge_sections -#endif - #ifndef bfd_elfNN_bfd_is_group_section #define bfd_elfNN_bfd_is_group_section bfd_elf_is_group_section #endif @@ -287,6 +282,9 @@ #ifndef bfd_elfNN_bfd_final_link #define bfd_elfNN_bfd_final_link bfd_elf_final_link #endif +#ifndef bfd_elfNN_bfd_merge_sections +#define bfd_elfNN_bfd_merge_sections _bfd_elf_merge_sections +#endif #else /* ! defined (elf_backend_relocate_section) */ /* If no backend relocate_section routine, use the generic linker. Note - this will prevent the port from being able to use some of @@ -310,6 +308,9 @@ #ifndef bfd_elfNN_bfd_final_link #define bfd_elfNN_bfd_final_link _bfd_generic_final_link #endif +#ifndef bfd_elfNN_bfd_merge_sections +#define bfd_elfNN_bfd_merge_sections bfd_generic_merge_sections +#endif #endif /* ! defined (elf_backend_relocate_section) */ #ifndef bfd_elfNN_bfd_link_just_syms diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c index 85737fc..0843803 100644 --- a/bfd/elfxx-x86.c +++ b/bfd/elfxx-x86.c @@ -745,6 +745,7 @@ _bfd_x86_elf_link_hash_table_create (bfd *abfd) ret->tls_get_addr = "__tls_get_addr"; ret->relative_r_type = R_X86_64_RELATIVE; ret->relative_r_name = "R_X86_64_RELATIVE"; + ret->ax_register = "RAX"; ret->elf_append_reloc = elf_append_rela; ret->elf_write_addend_in_got = _bfd_elf64_write_addend; } @@ -776,6 +777,7 @@ _bfd_x86_elf_link_hash_table_create (bfd *abfd) ret->pointer_r_type = R_386_32; ret->relative_r_type = R_386_RELATIVE; ret->relative_r_name = "R_386_RELATIVE"; + ret->ax_register = "EAX"; ret->elf_append_reloc = elf_append_rel; ret->elf_write_addend = _bfd_elf32_write_addend; ret->elf_write_addend_in_got = _bfd_elf32_write_addend; @@ -1815,7 +1817,8 @@ elf_x86_relative_reloc_compare (const void *pa, const void *pb) enum dynobj_sframe_plt_type { SFRAME_PLT = 1, - SFRAME_PLT_SEC = 2 + SFRAME_PLT_SEC = 2, + SFRAME_PLT_GOT = 3, }; /* Create SFrame stack trace info for the plt entries in the .plt section @@ -1829,7 +1832,6 @@ _bfd_x86_elf_create_sframe_plt (bfd *output_bfd, struct elf_x86_link_hash_table *htab; const struct elf_backend_data *bed; - bool plt0_generated_p; unsigned int plt0_entry_size; unsigned char func_info; uint32_t fre_type; @@ -1843,14 +1845,11 @@ _bfd_x86_elf_create_sframe_plt (bfd *output_bfd, unsigned plt_entry_size = 0; unsigned int num_pltn_fres = 0; unsigned int num_pltn_entries = 0; + const sframe_frame_row_entry * const *pltn_fres; bed = get_elf_backend_data (output_bfd); htab = elf_x86_hash_table (info, bed->target_id); /* Whether SFrame stack trace info for plt0 is to be generated. */ - plt0_generated_p = htab->plt.has_plt0; - plt0_entry_size - = (plt0_generated_p) ? htab->sframe_plt->plt0_entry_size : 0; - switch (plt_sec_type) { case SFRAME_PLT: @@ -1858,7 +1857,10 @@ _bfd_x86_elf_create_sframe_plt (bfd *output_bfd, ectx = &htab->plt_cfe_ctx; dpltsec = htab->elf.splt; - plt_entry_size = htab->plt.plt_entry_size; + plt0_entry_size + = htab->plt.has_plt0 ? htab->sframe_plt->plt0_entry_size : 0; + plt_entry_size = htab->sframe_plt->pltn_entry_size; + pltn_fres = htab->sframe_plt->pltn_fres; num_pltn_fres = htab->sframe_plt->pltn_num_fres; num_pltn_entries = (dpltsec->size - plt0_entry_size) / plt_entry_size; @@ -1868,14 +1870,32 @@ _bfd_x86_elf_create_sframe_plt (bfd *output_bfd, case SFRAME_PLT_SEC: { ectx = &htab->plt_second_cfe_ctx; - /* FIXME - this or htab->plt_second_sframe ? */ - dpltsec = htab->plt_second_eh_frame; + dpltsec = htab->plt_second; + + plt0_entry_size = 0; plt_entry_size = htab->sframe_plt->sec_pltn_entry_size; + pltn_fres = htab->sframe_plt->sec_pltn_fres; num_pltn_fres = htab->sframe_plt->sec_pltn_num_fres; num_pltn_entries = dpltsec->size / plt_entry_size; + break; } + case SFRAME_PLT_GOT: + { + ectx = &htab->plt_got_cfe_ctx; + dpltsec = htab->plt_got; + + plt0_entry_size = 0; + + plt_entry_size = htab->sframe_plt->plt_got_entry_size; + pltn_fres = htab->sframe_plt->plt_got_fres; + num_pltn_fres = htab->sframe_plt->plt_got_num_fres; + num_pltn_entries = dpltsec->size / plt_entry_size; + + break; + } + default: /* No other value is possible. */ return false; @@ -1895,7 +1915,7 @@ _bfd_x86_elf_create_sframe_plt (bfd *output_bfd, /* Add SFrame FDE and the associated FREs for plt0 if plt0 has been generated. */ - if (plt0_generated_p) + if (plt0_entry_size) { /* Add SFrame FDE for plt0, the function start address is updated later at _bfd_elf_merge_section_sframe time. */ @@ -1932,16 +1952,17 @@ _bfd_x86_elf_create_sframe_plt (bfd *output_bfd, plt0_entry_size, /* func start addr. */ dpltsec->size - plt0_entry_size, func_info, - 16, + plt_entry_size, 0 /* Num FREs. */); sframe_frame_row_entry pltn_fre; - /* Now add the FREs for pltn. Simply adding the two FREs suffices due + /* Now add the FREs for pltn. Simply adding the FREs suffices due to the usage of SFRAME_FDE_TYPE_PCMASK above. */ for (unsigned int j = 0; j < num_pltn_fres; j++) { - pltn_fre = *(htab->sframe_plt->pltn_fres[j]); - sframe_encoder_add_fre (*ectx, 1, &pltn_fre); + unsigned int func_idx = plt0_entry_size ? 1 : 0; + pltn_fre = *(pltn_fres[j]); + sframe_encoder_add_fre (*ectx, func_idx, &pltn_fre); } } @@ -1979,6 +2000,10 @@ _bfd_x86_elf_write_sframe_plt (bfd *output_bfd, ectx = htab->plt_second_cfe_ctx; sec = htab->plt_second_sframe; break; + case SFRAME_PLT_GOT: + ectx = htab->plt_got_cfe_ctx; + sec = htab->plt_got_sframe; + break; default: /* No other value is possible. */ return false; @@ -2506,7 +2531,18 @@ _bfd_x86_elf_late_size_sections (bfd *output_bfd, htab->plt_sframe->size = sizeof (sframe_header) + 1; } - /* FIXME - generate for .plt.got ? */ + if (htab->plt_got_sframe != NULL + && htab->plt_got != NULL + && htab->plt_got->size != 0 + && !bfd_is_abs_section (htab->plt_got->output_section)) + { + _bfd_x86_elf_create_sframe_plt (output_bfd, info, SFRAME_PLT_GOT); + /* FIXME - Dirty Hack. Set the size to something non-zero for now, + so that the section does not get stripped out below. The precise + size of this section is known only when the contents are + serialized in _bfd_x86_elf_write_sframe_plt. */ + htab->plt_got_sframe->size = sizeof (sframe_header) + 1; + } if (htab->plt_second_sframe != NULL && htab->plt_second != NULL @@ -2573,6 +2609,7 @@ _bfd_x86_elf_late_size_sections (bfd *output_bfd, || s == htab->plt_second_eh_frame || s == htab->plt_sframe || s == htab->plt_second_sframe + || s == htab->plt_got_sframe || s == htab->elf.sdynbss || s == htab->elf.sdynrelro) { @@ -2617,7 +2654,8 @@ _bfd_x86_elf_late_size_sections (bfd *output_bfd, /* Skip allocating contents for .sframe section as it is written out differently. See below. */ - if ((s == htab->plt_sframe) || (s == htab->plt_second_sframe)) + if ((s == htab->plt_sframe) || (s == htab->plt_second_sframe) + || (s == htab->plt_got_sframe)) continue; /* NB: Initially, the iplt section has minimal alignment to @@ -2678,10 +2716,16 @@ _bfd_x86_elf_late_size_sections (bfd *output_bfd, _bfd_x86_elf_write_sframe_plt (output_bfd, info, SFRAME_PLT); if (htab->plt_second_sframe != NULL - && htab->elf.splt != NULL - && htab->elf.splt->size != 0 + && htab->plt_second != NULL + && htab->plt_second->size != 0 && htab->plt_second_sframe->contents == NULL) _bfd_x86_elf_write_sframe_plt (output_bfd, info, SFRAME_PLT_SEC); + + if (htab->plt_got_sframe != NULL + && htab->plt_got != NULL + && htab->plt_got->size != 0 + && htab->plt_got_sframe->contents == NULL) + _bfd_x86_elf_write_sframe_plt (output_bfd, info, SFRAME_PLT_GOT); } if (resolved_plt != NULL @@ -2992,6 +3036,34 @@ _bfd_x86_elf_finish_dynamic_sections (bfd *output_bfd, return NULL; } } + + if (htab->plt_got_sframe != NULL + && htab->plt_got_sframe->contents != NULL) + { + if (htab->plt_got != NULL + && htab->plt_got->size != 0 + && (htab->plt_got->flags & SEC_EXCLUDE) == 0 + && htab->plt_got->output_section != NULL + && htab->plt_got_sframe->output_section != NULL) + { + bfd_vma plt_start = htab->plt_got->output_section->vma; + bfd_vma sframe_start + = (htab->plt_got_sframe->output_section->vma + + htab->plt_got_sframe->output_offset + + PLT_SFRAME_FDE_START_OFFSET); + bfd_put_signed_32 (dynobj, plt_start - sframe_start, + htab->plt_got_sframe->contents + + PLT_SFRAME_FDE_START_OFFSET); + } + if (htab->plt_got_sframe->sec_info_type == SEC_INFO_TYPE_SFRAME) + { + if (! _bfd_elf_merge_section_sframe (output_bfd, info, + htab->plt_got_sframe, + htab->plt_got_sframe->contents)) + return NULL; + } + } + if (htab->elf.sgot && htab->elf.sgot->size > 0) elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize = htab->got_entry_size; @@ -3211,15 +3283,14 @@ _bfd_x86_elf_link_report_tls_transition_error enum elf_x86_tls_error_type tls_error) { const char *name; + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + struct elf_x86_link_hash_table *htab + = elf_x86_hash_table (info, bed->target_id); if (h) name = h->root.root.string; else { - const struct elf_backend_data *bed - = get_elf_backend_data (abfd); - struct elf_x86_link_hash_table *htab - = elf_x86_hash_table (info, bed->target_id); if (htab == NULL) name = "*unknown*"; else @@ -3265,8 +3336,9 @@ _bfd_x86_elf_link_report_tls_transition_error info->callbacks->einfo /* xgettext:c-format */ (_("%pB(%pA+0x%v): relocation %s against `%s' must be used " - "in indirect CALL only\n"), - abfd, asect, rel->r_offset, from_reloc_name, name); + "in indirect CALL with %s register only\n"), + abfd, asect, rel->r_offset, from_reloc_name, name, + htab->ax_register); break; case elf_x86_tls_error_lea: @@ -4759,7 +4831,18 @@ _bfd_x86_elf_link_setup_gnu_properties htab->plt_second_sframe = sec; } - /* FIXME - add later for plt_got. */ + + /* .plt.got. */ + if (htab->plt_got != NULL) + { + sec = bfd_make_section_anyway_with_flags (dynobj, + ".sframe", + flags); + if (sec == NULL) + info->callbacks->einfo (_("%F%P: failed to create PLT GOT .sframe section\n")); + + htab->plt_got_sframe = sec; + } } } diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h index 5eef7b0..cd26e8f 100644 --- a/bfd/elfxx-x86.h +++ b/bfd/elfxx-x86.h @@ -401,6 +401,10 @@ struct elf_x86_sframe_plt unsigned int sec_pltn_entry_size; unsigned int sec_pltn_num_fres; const sframe_frame_row_entry *sec_pltn_fres[SFRAME_PLTN_MAX_NUM_FRES]; + + unsigned int plt_got_entry_size; + unsigned int plt_got_num_fres; + const sframe_frame_row_entry *plt_got_fres[SFRAME_PLTN_MAX_NUM_FRES]; }; struct elf_x86_lazy_plt_layout @@ -606,6 +610,8 @@ struct elf_x86_link_hash_table asection *plt_sframe; sframe_encoder_ctx *plt_second_cfe_ctx; asection *plt_second_sframe; + sframe_encoder_ctx *plt_got_cfe_ctx; + asection *plt_got_sframe; /* Parameters describing PLT generation, lazy or non-lazy. */ struct elf_x86_plt_layout plt; @@ -687,6 +693,7 @@ struct elf_x86_link_hash_table const char *dynamic_interpreter; const char *tls_get_addr; const char *relative_r_name; + const char *ax_register; void (*elf_append_reloc) (bfd *, asection *, Elf_Internal_Rela *); void (*elf_write_addend) (bfd *, uint64_t, void *); void (*elf_write_addend_in_got) (bfd *, uint64_t, void *); diff --git a/bfd/libbfd-in.h b/bfd/libbfd-in.h index f7f5773..950d797 100644 --- a/bfd/libbfd-in.h +++ b/bfd/libbfd-in.h @@ -889,22 +889,6 @@ _bfd_alloc_and_read (bfd *abfd, bfd_size_type asize, bfd_size_type rsize) return NULL; } -#ifdef USE_MMAP -extern void *_bfd_mmap_readonly_persistent - (bfd *, size_t) ATTRIBUTE_HIDDEN; -extern void *_bfd_mmap_readonly_temporary - (bfd *, size_t, void **, size_t *) ATTRIBUTE_HIDDEN; -extern void _bfd_munmap_readonly_temporary - (void *, size_t) ATTRIBUTE_HIDDEN; -#else -#define _bfd_mmap_readonly_persistent(abfd, rsize) \ - _bfd_alloc_and_read (abfd, rsize, rsize) -#define _bfd_munmap_readonly_temporary(ptr, rsize) free (ptr) -#endif - -extern bool _bfd_mmap_read_temporary - (void **, size_t *, void **, bfd *, bool) ATTRIBUTE_HIDDEN; - static inline void * _bfd_malloc_and_read (bfd *abfd, bfd_size_type asize, bfd_size_type rsize) { @@ -928,14 +912,34 @@ _bfd_malloc_and_read (bfd *abfd, bfd_size_type asize, bfd_size_type rsize) return NULL; } -#ifndef USE_MMAP +#ifdef USE_MMAP +extern void *_bfd_mmap_persistent + (bfd *, size_t) ATTRIBUTE_HIDDEN; +extern void *_bfd_mmap_temporary + (bfd *, size_t, void **, size_t *) ATTRIBUTE_HIDDEN; +extern void _bfd_munmap_temporary + (void *, size_t) ATTRIBUTE_HIDDEN; +#else +static inline void * +_bfd_mmap_persistent (bfd *abfd, size_t rsize) +{ + return _bfd_alloc_and_read (abfd, rsize, rsize); +} static inline void * -_bfd_mmap_readonly_temporary (bfd *abfd, size_t rsize, void **map_addr, - size_t *map_size) +_bfd_mmap_temporary (bfd *abfd, size_t rsize, void **map_addr, + size_t *map_size) { void *mem = _bfd_malloc_and_read (abfd, rsize, rsize); *map_addr = mem; *map_size = rsize; return mem; } +static inline void +_bfd_munmap_temporary (void *ptr, size_t rsize ATTRIBUTE_UNUSED) +{ + free (ptr); +} #endif + +extern bool _bfd_mmap_read_temporary + (void **, size_t *, void **, bfd *, bool) ATTRIBUTE_HIDDEN; diff --git a/bfd/libbfd.c b/bfd/libbfd.c index 5386847..4ab5bf4 100644 --- a/bfd/libbfd.c +++ b/bfd/libbfd.c @@ -1064,13 +1064,12 @@ bfd_allocate_mmapped_page (bfd *abfd, struct bfd_mmapped_entry **entry) return mmapped; } -/* Mmap a memory region of RSIZE bytes with PROT at the current offset. +/* Mmap a memory region of RSIZE bytes at the current file offset. Return mmap address and size in MAP_ADDR and MAP_SIZE. Return NULL on invalid input and MAP_FAILED for mmap failure. */ static void * -bfd_mmap_local (bfd *abfd, size_t rsize, int prot, void **map_addr, - size_t *map_size) +bfd_mmap_local (bfd *abfd, size_t rsize, void **map_addr, size_t *map_size) { /* We mmap on the underlying file. In an archive it might be nice to limit RSIZE to the element size, but that can be fuzzed and @@ -1092,18 +1091,18 @@ bfd_mmap_local (bfd *abfd, size_t rsize, int prot, void **map_addr, } void *mem; - mem = bfd_mmap (abfd, NULL, rsize, prot, MAP_PRIVATE, offset, - map_addr, map_size); + mem = bfd_mmap (abfd, NULL, rsize, PROT_READ | PROT_WRITE, MAP_PRIVATE, + offset, map_addr, map_size); return mem; } -/* Mmap a readonly memory region of RSIZE bytes at the current offset. +/* Mmap a memory region of RSIZE bytes at the current offset. Return mmap address and size in MAP_ADDR and MAP_SIZE. Return NULL on invalid input and MAP_FAILED for mmap failure. */ void * -_bfd_mmap_readonly_temporary (bfd *abfd, size_t rsize, void **map_addr, - size_t *map_size) +_bfd_mmap_temporary (bfd *abfd, size_t rsize, void **map_addr, + size_t *map_size) { /* Use mmap only if section size >= the minimum mmap section size. */ if (rsize < _bfd_minimum_mmap_size) @@ -1116,17 +1115,17 @@ _bfd_mmap_readonly_temporary (bfd *abfd, size_t rsize, void **map_addr, return mem; } - return bfd_mmap_local (abfd, rsize, PROT_READ, map_addr, map_size); + return bfd_mmap_local (abfd, rsize, map_addr, map_size); } /* Munmap RSIZE bytes at PTR. */ void -_bfd_munmap_readonly_temporary (void *ptr, size_t rsize) +_bfd_munmap_temporary (void *ptr, size_t rsize) { - /* NB: Since _bfd_munmap_readonly_temporary is called like free, PTR - may be NULL. Otherwise, PTR and RSIZE must be valid. If RSIZE is - 0, _bfd_malloc_and_read is called. */ + /* NB: Since _bfd_munmap_temporary is called like free, PTR may be + NULL. Otherwise, PTR and RSIZE must be valid. If RSIZE is 0, + free is called. */ if (ptr == NULL) return; if (rsize != 0) @@ -1138,11 +1137,11 @@ _bfd_munmap_readonly_temporary (void *ptr, size_t rsize) free (ptr); } -/* Mmap a readonly memory region of RSIZE bytes at the current offset. +/* Mmap a memory region of RSIZE bytes at the current offset. Return NULL on invalid input or mmap failure. */ void * -_bfd_mmap_readonly_persistent (bfd *abfd, size_t rsize) +_bfd_mmap_persistent (bfd *abfd, size_t rsize) { /* Use mmap only if section size >= the minimum mmap section size. */ if (rsize < _bfd_minimum_mmap_size) @@ -1150,7 +1149,7 @@ _bfd_mmap_readonly_persistent (bfd *abfd, size_t rsize) void *mem, *map_addr; size_t map_size; - mem = bfd_mmap_local (abfd, rsize, PROT_READ, &map_addr, &map_size); + mem = bfd_mmap_local (abfd, rsize, &map_addr, &map_size); if (mem == NULL) return mem; if (mem == MAP_FAILED) @@ -1213,9 +1212,7 @@ _bfd_mmap_read_temporary (void **data_p, size_t *size_p, && (abfd->flags & BFD_PLUGIN) == 0); if (use_mmmap) { - void *mmaped = _bfd_mmap_readonly_temporary (abfd, size, - mmap_base, - size_p); + void *mmaped = _bfd_mmap_temporary (abfd, size, mmap_base, size_p); /* MAP_FAILED is returned when called from GDB on an object with opncls_iovec. Use bfd_read in this case. */ if (mmaped != MAP_FAILED) @@ -1234,8 +1231,7 @@ _bfd_mmap_read_temporary (void **data_p, size_t *size_p, if (data == NULL) return false; *data_p = data; - /* NB: _bfd_munmap_readonly_temporary will free *MMAP_BASE if - *SIZE_P == 0. */ + /* NB: _bfd_munmap_temporary will free *MMAP_BASE if *SIZE_P == 0. */ *mmap_base = data; } else @@ -1302,12 +1298,9 @@ _bfd_generic_get_section_contents (bfd *abfd, || bfd_get_flavour (abfd) != bfd_target_elf_flavour) abort (); - int prot = ((section->reloc_count == 0) - ? PROT_READ : PROT_READ | PROT_WRITE); - - location = bfd_mmap_local - (abfd, count, prot, &elf_section_data (section)->contents_addr, - &elf_section_data (section)->contents_size); + location = bfd_mmap_local (abfd, count, + &elf_section_data (section)->contents_addr, + &elf_section_data (section)->contents_size); if (location == NULL) return false; diff --git a/bfd/libbfd.h b/bfd/libbfd.h index 5e8ed9e..5da7541 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -895,22 +895,6 @@ _bfd_alloc_and_read (bfd *abfd, bfd_size_type asize, bfd_size_type rsize) return NULL; } -#ifdef USE_MMAP -extern void *_bfd_mmap_readonly_persistent - (bfd *, size_t) ATTRIBUTE_HIDDEN; -extern void *_bfd_mmap_readonly_temporary - (bfd *, size_t, void **, size_t *) ATTRIBUTE_HIDDEN; -extern void _bfd_munmap_readonly_temporary - (void *, size_t) ATTRIBUTE_HIDDEN; -#else -#define _bfd_mmap_readonly_persistent(abfd, rsize) \ - _bfd_alloc_and_read (abfd, rsize, rsize) -#define _bfd_munmap_readonly_temporary(ptr, rsize) free (ptr) -#endif - -extern bool _bfd_mmap_read_temporary - (void **, size_t *, void **, bfd *, bool) ATTRIBUTE_HIDDEN; - static inline void * _bfd_malloc_and_read (bfd *abfd, bfd_size_type asize, bfd_size_type rsize) { @@ -934,17 +918,37 @@ _bfd_malloc_and_read (bfd *abfd, bfd_size_type asize, bfd_size_type rsize) return NULL; } -#ifndef USE_MMAP +#ifdef USE_MMAP +extern void *_bfd_mmap_persistent + (bfd *, size_t) ATTRIBUTE_HIDDEN; +extern void *_bfd_mmap_temporary + (bfd *, size_t, void **, size_t *) ATTRIBUTE_HIDDEN; +extern void _bfd_munmap_temporary + (void *, size_t) ATTRIBUTE_HIDDEN; +#else +static inline void * +_bfd_mmap_persistent (bfd *abfd, size_t rsize) +{ + return _bfd_alloc_and_read (abfd, rsize, rsize); +} static inline void * -_bfd_mmap_readonly_temporary (bfd *abfd, size_t rsize, void **map_addr, - size_t *map_size) +_bfd_mmap_temporary (bfd *abfd, size_t rsize, void **map_addr, + size_t *map_size) { void *mem = _bfd_malloc_and_read (abfd, rsize, rsize); *map_addr = mem; *map_size = rsize; return mem; } +static inline void +_bfd_munmap_temporary (void *ptr, size_t rsize ATTRIBUTE_UNUSED) +{ + free (ptr); +} #endif + +extern bool _bfd_mmap_read_temporary + (void **, size_t *, void **, bfd *, bool) ATTRIBUTE_HIDDEN; /* Extracted from libbfd.c. */ void *bfd_malloc (bfd_size_type /*size*/) ATTRIBUTE_HIDDEN; diff --git a/bfd/merge.c b/bfd/merge.c index 5c8e69b..a4b928d 100644 --- a/bfd/merge.c +++ b/bfd/merge.c @@ -73,8 +73,6 @@ struct sec_merge_hash_entry struct sec_merge_hash { struct bfd_hash_table table; - /* Next available index. */ - bfd_size_type size; /* First entity in the SEC_MERGE sections of this type. */ struct sec_merge_hash_entry *first; /* Last entity in the SEC_MERGE sections of this type. */ @@ -94,10 +92,6 @@ struct sec_merge_hash struct sec_merge_hash_entry **values; }; -/* True when given NEWCOUNT and NBUCKETS indicate that the hash table needs - resizing. */ -#define NEEDS_RESIZE(newcount, nbuckets) ((newcount) > (nbuckets) / 3 * 2) - struct sec_merge_sec_info; /* Information per merged blob. This is the unit of merging and is @@ -163,62 +157,75 @@ struct sec_merge_sec_info }; +/* True when COUNT+ADDED and NBUCKETS indicate that the hash table + needs resizing. */ + +static inline bool +needs_resize (unsigned int count, unsigned int added, unsigned int nbuckets) +{ + /* This doesn't consider the possibility of "count" + "added" + overflowing, because that can't happen given current usage. If + code calling this function changes then that assumption may no + longer be correct. Currently "added" is always 1 and "nbuckets" + is limited to 0x80000000. We'll attempt and fail resizing at + "count" of 0x55555555. */ + return count + added > nbuckets / 3 * 2; +} + /* Given a merge hash table TABLE and a number of entries to be - ADDED, possibly resize the table for this to fit without further - resizing. */ + ADDED, resize the table for this to fit. + Returns false if that can't be done for whatever reason. */ static bool -sec_merge_maybe_resize (struct sec_merge_hash *table, unsigned added) +sec_merge_resize (struct sec_merge_hash *table, unsigned added) { struct bfd_hash_table *bfdtab = &table->table; - if (NEEDS_RESIZE (bfdtab->count + added, table->nbuckets)) - { - unsigned i; - unsigned long newnb = table->nbuckets * 2; - struct sec_merge_hash_entry **newv; - uint64_t *newl; - unsigned long alloc; - - while (NEEDS_RESIZE (bfdtab->count + added, newnb)) - { - newnb *= 2; - if (!newnb) - return false; - } + unsigned i; + unsigned long newnb = table->nbuckets; + struct sec_merge_hash_entry **newv; + uint64_t *newl; + unsigned long alloc; - alloc = newnb * sizeof (newl[0]); - if (alloc / sizeof (newl[0]) != newnb) - return false; - newl = objalloc_alloc ((struct objalloc *) table->table.memory, alloc); - if (newl == NULL) - return false; - memset (newl, 0, alloc); - alloc = newnb * sizeof (newv[0]); - if (alloc / sizeof (newv[0]) != newnb) - return false; - newv = objalloc_alloc ((struct objalloc *) table->table.memory, alloc); - if (newv == NULL) + do + { + if (newnb >> (8 * sizeof(mapofs_type) - 1)) return false; - memset (newv, 0, alloc); + newnb *= 2; + } + while (needs_resize (bfdtab->count, added, newnb)); - for (i = 0; i < table->nbuckets; i++) + alloc = newnb * sizeof (newl[0]); + if (alloc / sizeof (newl[0]) != newnb) + return false; + newl = objalloc_alloc ((struct objalloc *) table->table.memory, alloc); + if (newl == NULL) + return false; + memset (newl, 0, alloc); + alloc = newnb * sizeof (newv[0]); + if (alloc / sizeof (newv[0]) != newnb) + return false; + newv = objalloc_alloc ((struct objalloc *) table->table.memory, alloc); + if (newv == NULL) + return false; + memset (newv, 0, alloc); + + for (i = 0; i < table->nbuckets; i++) + { + struct sec_merge_hash_entry *v = table->values[i]; + if (v) { - struct sec_merge_hash_entry *v = table->values[i]; - if (v) - { - uint32_t thishash = table->key_lens[i] >> 32; - unsigned idx = thishash & (newnb - 1); - while (newv[idx]) - idx = (idx + 1) & (newnb - 1); - newl[idx] = table->key_lens[i]; - newv[idx] = v; - } + uint32_t thishash = table->key_lens[i] >> 32; + unsigned idx = thishash & (newnb - 1); + while (newv[idx]) + idx = (idx + 1) & (newnb - 1); + newl[idx] = table->key_lens[i]; + newv[idx] = v; } - - table->key_lens = newl; - table->values = newv; - table->nbuckets = newnb; } + + table->key_lens = newl; + table->values = newv; + table->nbuckets = newnb; return true; } @@ -243,8 +250,23 @@ sec_merge_hash_insert (struct sec_merge_hash *table, hashp->alignment = 0; hashp->u.suffix = NULL; hashp->next = NULL; - // We must not need resizing, otherwise the estimation was wrong - BFD_ASSERT (!NEEDS_RESIZE (bfdtab->count + 1, table->nbuckets)); + + if (needs_resize (bfdtab->count, 1, table->nbuckets)) + { + if (!sec_merge_resize (table, 1)) + return NULL; + uint64_t *key_lens = table->key_lens; + unsigned int nbuckets = table->nbuckets; + _index = hash & (nbuckets - 1); + while (1) + { + uint64_t candlen = key_lens[_index]; + if (!(candlen & (uint32_t)-1)) + break; + _index = (_index + 1) & (nbuckets - 1); + } + } + bfdtab->count++; table->key_lens[_index] = (hash << 32) | (uint32_t)len; table->values[_index] = hashp; @@ -406,8 +428,6 @@ sec_merge_hash_lookup (struct sec_merge_hash *table, const char *string, return NULL; hashp->alignment = alignment; - table->size++; - BFD_ASSERT (table->size == table->table.count); if (table->first == NULL) table->first = hashp; else @@ -435,7 +455,6 @@ sec_merge_init (unsigned int entsize, bool strings) return NULL; } - table->size = 0; table->first = NULL; table->last = NULL; table->entsize = entsize; @@ -698,7 +717,9 @@ _bfd_add_merge_section (bfd *abfd, void **psinfo, asection *sec, } /* Record one whole input section (described by SECINFO) into the hash table - SINFO. */ + SINFO. Returns true when section is completely recorded, and false when + it wasn't recorded but we can continue (e.g. by simply not deduplicating + this section). */ static bool record_section (struct sec_merge_info *sinfo, @@ -732,15 +753,6 @@ record_section (struct sec_merge_info *sinfo, /* Now populate the hash table and offset mapping. */ - /* Presize the hash table for what we're going to add. We overestimate - quite a bit, but if it turns out to be too much then other sections - merged into this area will make use of that as well. */ - if (!sec_merge_maybe_resize (sinfo->htab, 1 + sec->size / 2)) - { - bfd_set_error (bfd_error_no_memory); - goto error_return; - } - /* Walk through the contents, calculate hashes and length of all blobs (strings or fixed-size entries) we find and fill the hash and offset tables. */ @@ -793,8 +805,6 @@ record_section (struct sec_merge_info *sinfo, error_return: free (contents); contents = NULL; - for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next) - *secinfo->psecinfo = NULL; return false; } @@ -876,7 +886,7 @@ merge_strings (struct sec_merge_info *sinfo) unsigned int alignment = 0; /* Now sort the strings */ - amt = sinfo->htab->size * sizeof (struct sec_merge_hash_entry *); + amt = sinfo->htab->table.count * sizeof (struct sec_merge_hash_entry *); array = (struct sec_merge_hash_entry **) bfd_malloc (amt); if (array == NULL) return NULL; @@ -896,10 +906,10 @@ merge_strings (struct sec_merge_info *sinfo) } } - sinfo->htab->size = a - array; - if (sinfo->htab->size != 0) + size_t asize = a - array; + if (asize != 0) { - qsort (array, (size_t) sinfo->htab->size, + qsort (array, asize, sizeof (struct sec_merge_hash_entry *), (alignment != (unsigned) -1 && alignment > sinfo->htab->entsize ? strrevcmp_align : strrevcmp)); @@ -983,24 +993,20 @@ _bfd_merge_sections (bfd *abfd, /* Record the sections into the hash table. */ align = 1; for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next) - if (secinfo->sec->flags & SEC_EXCLUDE) + if (secinfo->sec->flags & SEC_EXCLUDE + || !record_section (sinfo, secinfo)) { *secinfo->psecinfo = NULL; if (remove_hook) (*remove_hook) (abfd, secinfo->sec); } - else + else if (align) { - if (!record_section (sinfo, secinfo)) - return false; - if (align) - { - unsigned int opb = bfd_octets_per_byte (abfd, secinfo->sec); - - align = (bfd_size_type) 1 << secinfo->sec->alignment_power; - if (((secinfo->sec->size / opb) & (align - 1)) != 0) - align = 0; - } + unsigned int opb = bfd_octets_per_byte (abfd, secinfo->sec); + + align = (bfd_size_type) 1 << secinfo->sec->alignment_power; + if (((secinfo->sec->size / opb) & (align - 1)) != 0) + align = 0; } if (sinfo->htab->first == NULL) @@ -1043,7 +1049,8 @@ _bfd_merge_sections (bfd *abfd, /* Finally remove all input sections which have not made it into the hash table at all. */ for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next) - if (secinfo->first_str == NULL) + if (secinfo->first_str == NULL + && secinfo->sec->sec_info_type == SEC_INFO_TYPE_MERGE) secinfo->sec->flags |= SEC_EXCLUDE | SEC_KEEP; } @@ -412,7 +412,8 @@ pdb_allocate_block (uint32_t *num_blocks, uint32_t block_size) static bool pdb_write_directory (bfd *abfd, uint32_t block_size, uint32_t num_files, - uint32_t block_map_addr, uint32_t * num_blocks) + uint32_t block_map_addr, uint32_t * num_blocks, + uint32_t *stream0_start) { char tmp[sizeof (uint32_t)]; uint32_t block, left, block_map_off; @@ -561,6 +562,9 @@ pdb_write_directory (bfd *abfd, uint32_t block_size, uint32_t num_files, return false; } + if (arelt == abfd->archive_head && i == 0) + *stream0_start = file_block; + left -= sizeof (uint32_t); /* Read file contents into buffer. */ @@ -617,7 +621,8 @@ pdb_write_directory (bfd *abfd, uint32_t block_size, uint32_t num_files, } static bool -pdb_write_bitmap (bfd *abfd, uint32_t block_size, uint32_t num_blocks) +pdb_write_bitmap (bfd *abfd, uint32_t block_size, uint32_t num_blocks, + uint32_t stream0_start) { char *buf; uint32_t num_intervals = (num_blocks + block_size - 1) / block_size; @@ -626,8 +631,6 @@ pdb_write_bitmap (bfd *abfd, uint32_t block_size, uint32_t num_blocks) if (!buf) return false; - num_blocks--; /* Superblock not included. */ - for (uint32_t i = 0; i < num_intervals; i++) { if (bfd_seek (abfd, ((i * block_size) + 1) * block_size, SEEK_SET)) @@ -636,8 +639,8 @@ pdb_write_bitmap (bfd *abfd, uint32_t block_size, uint32_t num_blocks) return false; } - /* All of our blocks are contiguous, making our free block map simple. - 0 = used, 1 = free. */ + /* All of our blocks are contiguous, making our free block map + relatively simple. 0 = used, 1 = free. */ if (num_blocks >= 8) memset (buf, 0, @@ -650,7 +653,7 @@ pdb_write_bitmap (bfd *abfd, uint32_t block_size, uint32_t num_blocks) if (num_blocks % 8) { - buf[off] = (1 << (8 - (num_blocks % 8))) - 1; + buf[off] = 256 - (1 << (num_blocks % 8)); off++; } @@ -658,6 +661,40 @@ pdb_write_bitmap (bfd *abfd, uint32_t block_size, uint32_t num_blocks) memset (buf + off, 0xff, block_size - off); } + /* Mark the blocks allocated to stream 0 as free. This is because stream + 0 is intended to be used for the previous MSF directory, to allow + atomic updates. This doesn't apply to us, as we rewrite the whole + file whenever any change is made. */ + + if (i == 0 && abfd->archive_head) + { + bfd *arelt = abfd->archive_head; + uint32_t stream0_blocks = + (bfd_get_size (arelt) + block_size - 1) / block_size; + + if (stream0_start % 8) + { + unsigned int high_bit; + + high_bit = (stream0_start % 8) + stream0_blocks; + if (high_bit > 8) + high_bit = 8; + + buf[stream0_start / 8] |= + (1 << high_bit) - (1 << (stream0_start % 8)); + + stream0_blocks -= high_bit - (stream0_start % 8); + stream0_start += high_bit - (stream0_start % 8); + } + + memset (buf + (stream0_start / 8), 0xff, stream0_blocks / 8); + stream0_start += stream0_blocks / 8; + stream0_blocks %= 8; + + if (stream0_blocks > 0) + buf[stream0_start / 8] |= (1 << stream0_blocks) - 1; + } + if (num_blocks < block_size * 8) num_blocks = 0; else @@ -681,6 +718,7 @@ pdb_write_contents (bfd *abfd) uint32_t num_blocks; uint32_t num_files = 0; uint32_t num_directory_bytes = sizeof (uint32_t); + uint32_t stream0_start = 0; bfd *arelt; if (bfd_write (pdb_magic, sizeof (pdb_magic), abfd) != sizeof (pdb_magic)) @@ -735,10 +773,11 @@ pdb_write_contents (bfd *abfd) return false; if (!pdb_write_directory - (abfd, block_size, num_files, block_map_addr, &num_blocks)) + (abfd, block_size, num_files, block_map_addr, &num_blocks, + &stream0_start)) return false; - if (!pdb_write_bitmap (abfd, block_size, num_blocks)) + if (!pdb_write_bitmap (abfd, block_size, num_blocks, stream0_start)) return false; /* Write num_blocks now we know it. */ diff --git a/bfd/peXXigen.c b/bfd/peXXigen.c index 51b567e..c09d16e 100644 --- a/bfd/peXXigen.c +++ b/bfd/peXXigen.c @@ -699,8 +699,8 @@ _bfd_XXi_swap_aouthdr_out (bfd * abfd, void * in, void * out) for the image size. */ if (coff_section_data (abfd, sec) != NULL && pei_section_data (abfd, sec) != NULL) - isize = (sec->vma - extra->ImageBase - + SA (FA (pei_section_data (abfd, sec)->virt_size))); + isize = SA (sec->vma - extra->ImageBase + + FA (pei_section_data (abfd, sec)->virt_size)); } aouthdr_in->dsize = dsize; @@ -210,16 +210,18 @@ bfd_pef_print_symbol (bfd *abfd, bfd_print_symbol_type how) { FILE *file = (FILE *) afile; + const char *symname = (symbol->name != bfd_symbol_error_name + ? symbol->name : _("<corrupt>")); switch (how) { case bfd_print_symbol_name: - fprintf (file, "%s", symbol->name); + fprintf (file, "%s", symname); break; default: bfd_print_symbol_vandf (abfd, (void *) file, symbol); - fprintf (file, " %-5s %s", symbol->section->name, symbol->name); - if (startswith (symbol->name, "__traceback_")) + fprintf (file, " %-5s %s", symbol->section->name, symname); + if (startswith (symname, "__traceback_")) { unsigned char *buf; size_t offset = symbol->value + 4; diff --git a/bfd/peicode.h b/bfd/peicode.h index 11807ef..1a084fd 100644 --- a/bfd/peicode.h +++ b/bfd/peicode.h @@ -127,7 +127,7 @@ bfd_cleanup coff_real_object_p #ifndef NO_COFF_RELOCS static void -coff_swap_reloc_in (bfd * abfd, void * src, void * dst) +coff_swap_reloc_in (bfd *abfd, void *src, void *dst) { RELOC *reloc_src = (RELOC *) src; struct internal_reloc *reloc_dst = (struct internal_reloc *) dst; @@ -141,7 +141,7 @@ coff_swap_reloc_in (bfd * abfd, void * src, void * dst) } static unsigned int -coff_swap_reloc_out (bfd * abfd, void * src, void * dst) +coff_swap_reloc_out (bfd *abfd, void *src, void *dst) { struct internal_reloc *reloc_src = (struct internal_reloc *) src; struct external_reloc *reloc_dst = (struct external_reloc *) dst; @@ -166,7 +166,7 @@ coff_swap_reloc_out (bfd * abfd, void * src, void * dst) #endif static void -coff_swap_filehdr_in (bfd * abfd, void * src, void * dst) +coff_swap_filehdr_in (bfd *abfd, void *src, void *dst) { FILHDR *filehdr_src = (FILHDR *) src; struct internal_filehdr *filehdr_dst = (struct internal_filehdr *) dst; @@ -202,7 +202,7 @@ coff_swap_filehdr_in (bfd * abfd, void * src, void * dst) #endif static void -coff_swap_scnhdr_in (bfd * abfd, void * ext, void * in) +coff_swap_scnhdr_in (bfd *abfd, void *ext, void *in) { SCNHDR *scnhdr_ext = (SCNHDR *) ext; struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in; @@ -233,7 +233,8 @@ coff_swap_scnhdr_in (bfd * abfd, void * ext, void * in) { scnhdr_int->s_vaddr += pe_data (abfd)->pe_opthdr.ImageBase; /* Do not cut upper 32-bits for 64-bit vma. */ -#if !defined(COFF_WITH_pex64) && !defined(COFF_WITH_peAArch64) && !defined(COFF_WITH_peLoongArch64) && !defined(COFF_WITH_peRiscV64) +#if (!defined(COFF_WITH_pex64) && !defined(COFF_WITH_peAArch64) \ + && !defined(COFF_WITH_peLoongArch64) && !defined(COFF_WITH_peRiscV64)) scnhdr_int->s_vaddr &= 0xffffffff; #endif } @@ -256,7 +257,7 @@ coff_swap_scnhdr_in (bfd * abfd, void * ext, void * in) } static bool -pe_mkobject (bfd * abfd) +pe_mkobject (bfd *abfd) { /* Some x86 code followed by an ascii string. */ static const char default_dos_message[64] = { @@ -290,9 +291,9 @@ pe_mkobject (bfd * abfd) /* Create the COFF backend specific information. */ static void * -pe_mkobject_hook (bfd * abfd, - void * filehdr, - void * aouthdr ATTRIBUTE_UNUSED) +pe_mkobject_hook (bfd *abfd, + void *filehdr, + void *aouthdr ATTRIBUTE_UNUSED) { struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; pe_data_type *pe; @@ -344,7 +345,7 @@ pe_mkobject_hook (bfd * abfd, } static bool -pe_print_private_bfd_data (bfd *abfd, void * vfile) +pe_print_private_bfd_data (bfd *abfd, void *vfile) { FILE *file = (FILE *) vfile; @@ -418,17 +419,17 @@ pe_bfd_copy_private_bfd_data (bfd *ibfd, bfd *obfd) #define NUM_ILF_SECTIONS 6 #define NUM_ILF_SYMS (2 + NUM_ILF_SECTIONS) -#define SIZEOF_ILF_SYMS (NUM_ILF_SYMS * sizeof (* vars.sym_cache)) -#define SIZEOF_ILF_SYM_TABLE (NUM_ILF_SYMS * sizeof (* vars.sym_table)) -#define SIZEOF_ILF_NATIVE_SYMS (NUM_ILF_SYMS * sizeof (* vars.native_syms)) -#define SIZEOF_ILF_SYM_PTR_TABLE (NUM_ILF_SYMS * sizeof (* vars.sym_ptr_table)) -#define SIZEOF_ILF_EXT_SYMS (NUM_ILF_SYMS * sizeof (* vars.esym_table)) -#define SIZEOF_ILF_RELOCS (NUM_ILF_RELOCS * sizeof (* vars.reltab)) -#define SIZEOF_ILF_INT_RELOCS (NUM_ILF_RELOCS * sizeof (* vars.int_reltab)) +#define SIZEOF_ILF_SYMS (NUM_ILF_SYMS * sizeof (*vars.sym_cache)) +#define SIZEOF_ILF_SYM_TABLE (NUM_ILF_SYMS * sizeof (*vars.sym_table)) +#define SIZEOF_ILF_NATIVE_SYMS (NUM_ILF_SYMS * sizeof (*vars.native_syms)) +#define SIZEOF_ILF_SYM_PTR_TABLE (NUM_ILF_SYMS * sizeof (*vars.sym_ptr_table)) +#define SIZEOF_ILF_EXT_SYMS (NUM_ILF_SYMS * sizeof (*vars.esym_table)) +#define SIZEOF_ILF_RELOCS (NUM_ILF_RELOCS * sizeof (*vars.reltab)) +#define SIZEOF_ILF_INT_RELOCS (NUM_ILF_RELOCS * sizeof (*vars.int_reltab)) #define SIZEOF_ILF_STRINGS (strlen (symbol_name) * 2 + 8 \ - + 21 + strlen (source_dll) \ - + NUM_ILF_SECTIONS * 9 \ - + STRING_SIZE_SIZE) + + 21 + strlen (source_dll) \ + + NUM_ILF_SECTIONS * 9 \ + + STRING_SIZE_SIZE) #define SIZEOF_IDATA2 (5 * 4) /* For PEx64 idata4 & 5 have thumb size of 8 bytes. */ @@ -440,9 +441,10 @@ pe_bfd_copy_private_bfd_data (bfd *ibfd, bfd *obfd) #define SIZEOF_IDATA5 (1 * 4) #endif -#define SIZEOF_IDATA6 (2 + strlen (symbol_name) + 1 + 1) +#define SIZEOF_IDATA6 (2 + strlen (import_name) + 1 + 1) #define SIZEOF_IDATA7 (strlen (source_dll) + 1 + 1) -#define SIZEOF_ILF_SECTIONS (NUM_ILF_SECTIONS * sizeof (struct coff_section_tdata)) +#define SIZEOF_ILF_SECTIONS (NUM_ILF_SECTIONS \ + * sizeof (struct coff_section_tdata)) #define ILF_DATA_SIZE \ + SIZEOF_ILF_SYMS \ @@ -470,8 +472,8 @@ pe_ILF_make_a_symbol_reloc (pe_ILF_vars * vars, struct bfd_symbol ** sym, unsigned int sym_index) { - arelent * entry; - struct internal_reloc * internal; + arelent *entry; + struct internal_reloc *internal; entry = vars->reltab + vars->relcount; internal = vars->int_reltab + vars->relcount; @@ -505,8 +507,8 @@ pe_ILF_make_a_reloc (pe_ILF_vars * vars, /* Move the queued relocs into the given section. */ static void -pe_ILF_save_relocs (pe_ILF_vars * vars, - asection_ptr sec) +pe_ILF_save_relocs (pe_ILF_vars *vars, + asection_ptr sec) { /* Make sure that there is somewhere to store the internal relocs. */ if (coff_section_data (vars->abfd, sec) == NULL) @@ -535,9 +537,9 @@ pe_ILF_make_a_symbol (pe_ILF_vars * vars, asection_ptr section, flagword extra_flags) { - coff_symbol_type * sym; - combined_entry_type * ent; - SYMENT * esym; + coff_symbol_type *sym; + combined_entry_type *ent; + SYMENT *esym; unsigned short sclass; if (extra_flags & BSF_LOCAL) @@ -590,8 +592,8 @@ pe_ILF_make_a_symbol (pe_ILF_vars * vars, sym->symbol.section = section; sym->native = ent; - * vars->table_ptr = vars->sym_index; - * vars->sym_ptr_ptr = sym; + *vars->table_ptr = vars->sym_index; + *vars->sym_ptr_ptr = sym; /* Adjust pointers for the next symbol. */ vars->sym_index ++; @@ -792,7 +794,8 @@ pe_ILF_build_a_bfd (bfd * abfd, char * symbol_name, char * source_dll, unsigned int ordinal, - unsigned int types) + unsigned int types, + char * import_name) { bfd_byte * ptr; pe_ILF_vars vars; @@ -834,6 +837,17 @@ pe_ILF_build_a_bfd (bfd * abfd, case IMPORT_NAME: case IMPORT_NAME_NOPREFIX: case IMPORT_NAME_UNDECORATE: + import_name = symbol_name; + break; + + case IMPORT_NAME_EXPORTAS: + if (!import_name || !import_name[0]) + { + _bfd_error_handler (_("%pB: missing import name for " + "IMPORT_NAME_EXPORTAS for %s"), + abfd, symbol_name); + return false; + } break; default: @@ -922,8 +936,8 @@ pe_ILF_build_a_bfd (bfd * abfd, Note we do not create a .idata$3 section as this is created for us by the linker script. */ - id4 = pe_ILF_make_a_section (& vars, ".idata$4", SIZEOF_IDATA4, 0); - id5 = pe_ILF_make_a_section (& vars, ".idata$5", SIZEOF_IDATA5, 0); + id4 = pe_ILF_make_a_section (&vars, ".idata$4", SIZEOF_IDATA4, 0); + id5 = pe_ILF_make_a_section (&vars, ".idata$5", SIZEOF_IDATA5, 0); if (id4 == NULL || id5 == NULL) goto error_return; @@ -934,28 +948,29 @@ pe_ILF_build_a_bfd (bfd * abfd, /* See PR 20907 for a reproducer. */ goto error_return; -#if defined(COFF_WITH_pex64) || defined(COFF_WITH_peAArch64) || defined(COFF_WITH_peLoongArch64) || defined (COFF_WITH_peRiscV64) +#if (defined(COFF_WITH_pex64) || defined(COFF_WITH_peAArch64) \ + || defined(COFF_WITH_peLoongArch64) || defined (COFF_WITH_peRiscV64)) ((unsigned int *) id4->contents)[0] = ordinal; ((unsigned int *) id4->contents)[1] = 0x80000000; ((unsigned int *) id5->contents)[0] = ordinal; ((unsigned int *) id5->contents)[1] = 0x80000000; #else - * (unsigned int *) id4->contents = ordinal | 0x80000000; - * (unsigned int *) id5->contents = ordinal | 0x80000000; + ((unsigned int *) id4->contents)[0] = ordinal | 0x80000000; + ((unsigned int *) id5->contents)[0] = ordinal | 0x80000000; #endif } else { - char * symbol; + char *symbol; unsigned int len; /* Create .idata$6 - the Hint Name Table. */ - id6 = pe_ILF_make_a_section (& vars, ".idata$6", SIZEOF_IDATA6, 0); + id6 = pe_ILF_make_a_section (&vars, ".idata$6", SIZEOF_IDATA6, 0); if (id6 == NULL) goto error_return; /* If necessary, trim the import symbol name. */ - symbol = symbol_name; + symbol = import_name; /* As used by MS compiler, '_', '@', and '?' are alternative forms of USER_LABEL_PREFIX, with '?' for c++ mangled names, @@ -964,7 +979,8 @@ pe_ILF_build_a_bfd (bfd * abfd, IMPORT_NAME_NOPREFIX and IMPORT_NAME_UNDECORATE as per the PE COFF 6.0 spec (section 8.3, Import Name Type). */ - if (import_name_type != IMPORT_NAME) + if (import_name_type != IMPORT_NAME + && import_name_type != IMPORT_NAME_EXPORTAS) { char c = symbol[0]; @@ -1002,11 +1018,12 @@ pe_ILF_build_a_bfd (bfd * abfd, } /* Create an import symbol. */ - pe_ILF_make_a_symbol (& vars, "__imp_", symbol_name, id5, 0); + pe_ILF_make_a_symbol (&vars, "__imp_", symbol_name, id5, 0); imp_sym = vars.sym_ptr_ptr - 1; imp_index = vars.sym_index - 1; - /* Create extra sections depending upon the type of import we are dealing with. */ + /* Create extra sections depending upon the type of import we are + dealing with. */ switch (import_type) { int i; @@ -1027,7 +1044,7 @@ pe_ILF_build_a_bfd (bfd * abfd, abort (); /* Create the .text section. */ - text = pe_ILF_make_a_section (& vars, ".text", jtab[i].size, SEC_CODE); + text = pe_ILF_make_a_section (&vars, ".text", jtab[i].size, SEC_CODE); if (text == NULL) goto error_return; @@ -1061,7 +1078,7 @@ pe_ILF_build_a_bfd (bfd * abfd, BFD_RELOC_32, (asymbol **) imp_sym, imp_index); - pe_ILF_save_relocs (& vars, text); + pe_ILF_save_relocs (&vars, text); break; case IMPORT_DATA: @@ -1076,7 +1093,7 @@ pe_ILF_build_a_bfd (bfd * abfd, switch (import_type) { case IMPORT_CODE: - pe_ILF_make_a_symbol (& vars, "", symbol_name, text, + pe_ILF_make_a_symbol (&vars, "", symbol_name, text, BSF_NOT_AT_END | BSF_FUNCTION); break; @@ -1093,30 +1110,31 @@ pe_ILF_build_a_bfd (bfd * abfd, /* Create an import symbol for the DLL, without the .dll suffix. */ ptr = (bfd_byte *) strrchr (source_dll, '.'); if (ptr) - * ptr = 0; - pe_ILF_make_a_symbol (& vars, "__IMPORT_DESCRIPTOR_", source_dll, NULL, 0); + *ptr = 0; + pe_ILF_make_a_symbol (&vars, "__IMPORT_DESCRIPTOR_", source_dll, NULL, 0); if (ptr) - * ptr = '.'; + *ptr = '.'; /* Initialise the bfd. */ - memset (& internal_f, 0, sizeof (internal_f)); + memset (&internal_f, 0, sizeof (internal_f)); internal_f.f_magic = magic; internal_f.f_symptr = 0; internal_f.f_nsyms = 0; internal_f.f_flags = F_AR32WR | F_LNNO; /* XXX is this correct ? */ - if ( ! bfd_set_start_address (abfd, (bfd_vma) 0) - || ! bfd_coff_set_arch_mach_hook (abfd, & internal_f)) + if (!bfd_set_start_address (abfd, (bfd_vma) 0) + || !bfd_coff_set_arch_mach_hook (abfd, &internal_f)) goto error_return; - if (bfd_coff_mkobject_hook (abfd, (void *) & internal_f, NULL) == NULL) + if (bfd_coff_mkobject_hook (abfd, (void *) &internal_f, NULL) == NULL) goto error_return; obj_pe (abfd) = true; #ifdef THUMBPEMAGIC if (vars.magic == THUMBPEMAGIC) - /* Stop some linker warnings about thumb code not supporting interworking. */ + /* Stop some linker warnings about thumb code not supporting + interworking. */ coff_data (abfd)->flags |= F_INTERWORK | F_INTERWORK_SET; #endif @@ -1173,12 +1191,13 @@ pe_ILF_cleanup (bfd *abfd) Decode the element and return the appropriate target. */ static bfd_cleanup -pe_ILF_object_p (bfd * abfd) +pe_ILF_object_p (bfd *abfd) { bfd_byte buffer[14]; bfd_byte * ptr; char * symbol_name; char * source_dll; + char * import_name; unsigned int machine; bfd_size_type size; unsigned int ordinal; @@ -1266,7 +1285,7 @@ pe_ILF_object_p (bfd * abfd) { extern const bfd_target TARGET_LITTLE_SYM; - if (abfd->xvec == & TARGET_LITTLE_SYM) + if (abfd->xvec == &TARGET_LITTLE_SYM) magic = THUMBPEMAGIC; } #endif @@ -1340,9 +1359,24 @@ pe_ILF_object_p (bfd * abfd) return NULL; } + /* An ILF file may contain a third string, after source_dll; this is + used for IMPORT_NAME_EXPORTAS. We know from above that the whole + block of data is null terminated, ptr[size-1]==0, but we don't + know how many individual null terminated strings we have in there. + + First find the end of source_dll. */ + import_name = source_dll + strlen (source_dll) + 1; + if ((bfd_byte *) import_name >= ptr + size) + { + /* If this points at the end of the ptr+size block, we only had + two strings. */ + import_name = NULL; + } + /* Now construct the bfd. */ if (! pe_ILF_build_a_bfd (abfd, magic, symbol_name, - source_dll, ordinal, types)) + source_dll, ordinal, types, + import_name)) { bfd_release (abfd, ptr); return NULL; @@ -1424,12 +1458,14 @@ pe_bfd_read_buildid (bfd *abfd) (file_ptr) idd.PointerToRawData, idd.SizeOfData, cvinfo, NULL)) { - struct bfd_build_id* build_id = bfd_alloc (abfd, - sizeof (struct bfd_build_id) + cvinfo->SignatureLength); + struct bfd_build_id *build_id; + size_t bidlen = sizeof (*build_id) + cvinfo->SignatureLength; + + build_id = bfd_alloc (abfd, bidlen); if (build_id) { build_id->size = cvinfo->SignatureLength; - memcpy(build_id->data, cvinfo->Signature, + memcpy(build_id->data, cvinfo->Signature, cvinfo->SignatureLength); abfd->build_id = build_id; } @@ -1442,7 +1478,7 @@ pe_bfd_read_buildid (bfd *abfd) } static bfd_cleanup -pe_bfd_object_p (bfd * abfd) +pe_bfd_object_p (bfd *abfd) { bfd_byte buffer[6]; struct external_DOS_hdr dos_hdr; @@ -1527,7 +1563,7 @@ pe_bfd_object_p (bfd * abfd) if (opt_hdr_size != 0) { bfd_size_type amt = opt_hdr_size; - bfd_byte * opthdr; + bfd_byte *opthdr; /* PR 17521 file: 230-131433-0.004. */ if (amt < sizeof (PEAOUTHDR)) @@ -1561,7 +1597,7 @@ pe_bfd_object_p (bfd * abfd) || a->SectionAlignment >= 0x80000000) { _bfd_error_handler (_("%pB: adjusting invalid SectionAlignment"), - abfd); + abfd); a->SectionAlignment &= -a->SectionAlignment; if (a->SectionAlignment >= 0x80000000) a->SectionAlignment = 0x40000000; diff --git a/bfd/plugin.c b/bfd/plugin.c index 026654f..de2137f 100644 --- a/bfd/plugin.c +++ b/bfd/plugin.c @@ -329,13 +329,23 @@ try_claim (bfd *abfd) struct ld_plugin_input_file file; file.handle = abfd; - if (bfd_plugin_open_input (abfd, &file) - && current_plugin->claim_file) + if (bfd_plugin_open_input (abfd, &file)) { - current_plugin->claim_file (&file, &claimed); - bfd_plugin_close_file_descriptor ((abfd->my_archive != NULL - ? abfd : NULL), - file.fd); + bool claim_file_called = false; + if (current_plugin->claim_file_v2) + { + current_plugin->claim_file_v2 (&file, &claimed, false); + claim_file_called = true; + } + else if (current_plugin->claim_file) + { + current_plugin->claim_file (&file, &claimed); + claim_file_called = true; + } + if (claim_file_called) + bfd_plugin_close_file_descriptor ((abfd->my_archive != NULL + ? abfd : NULL), + file.fd); } return claimed; @@ -586,8 +596,12 @@ load_plugin (bfd *abfd) static bfd_cleanup bfd_plugin_object_p (bfd *abfd) { + /* Since ld_plugin_object_p is called only for linker command-line input + objects, pass true to ld_plugin_object_p so that the same input IR + file won't be included twice if the LDPT_REGISTER_CLAIM_FILE_HOOK_V2 + isn't used. */ if (ld_plugin_object_p) - return ld_plugin_object_p (abfd, false); + return ld_plugin_object_p (abfd, true); if (abfd->plugin_format == bfd_plugin_unknown && !load_plugin (abfd)) return NULL; @@ -342,6 +342,11 @@ EXTERNAL . const char *stab_name; {* String for stab type. *} .} symbol_info; . +.{* An empty string that will not match the address of any other +. symbol name, even unnamed local symbols which will also have empty +. string names. This can be used to flag a symbol as corrupt if its +. name uses an out of range string table index. *} +.extern const char bfd_symbol_error_name[]; */ #include "sysdep.h" @@ -351,6 +356,8 @@ EXTERNAL #include "bfdlink.h" #include "aout/stab_gnu.h" +const char bfd_symbol_error_name[] = { 0 }; + /* DOCDD INODE @@ -394,7 +401,7 @@ bfd_is_local_label (bfd *abfd, asymbol *sym) if we didn't reject them here. */ if ((sym->flags & (BSF_GLOBAL | BSF_WEAK | BSF_FILE | BSF_SECTION_SYM)) != 0) return false; - if (sym->name == NULL) + if (sym->name == NULL || sym->name == bfd_symbol_error_name) return false; return bfd_is_local_label_name (abfd, sym->name); } @@ -777,7 +784,8 @@ bfd_symbol_info (asymbol *symbol, symbol_info *ret) else ret->value = symbol->value + symbol->section->vma; - ret->name = symbol->name; + ret->name = (symbol->name != bfd_symbol_error_name + ? symbol->name : _("<corrupt>")); } /* diff --git a/bfd/tekhex.c b/bfd/tekhex.c index 96022c5..b305c1f 100644 --- a/bfd/tekhex.c +++ b/bfd/tekhex.c @@ -361,6 +361,7 @@ first_phase (bfd *abfd, int type, char *src, char * src_end) { asection *section, *alt_section; unsigned int len; + bfd_vma addr; bfd_vma val; char sym[17]; /* A symbol can only be 16chars long. */ @@ -368,20 +369,16 @@ first_phase (bfd *abfd, int type, char *src, char * src_end) { case '6': /* Data record - read it and store it. */ - { - bfd_vma addr; - - if (!getvalue (&src, &addr, src_end)) - return false; - - while (*src && src < src_end - 1) - { - insert_byte (abfd, HEX (src), addr); - src += 2; - addr++; - } - return true; - } + if (!getvalue (&src, &addr, src_end)) + return false; + + while (*src && src < src_end - 1) + { + insert_byte (abfd, HEX (src), addr); + src += 2; + addr++; + } + return true; case '3': /* Symbol record, read the segment. */ @@ -395,7 +392,7 @@ first_phase (bfd *abfd, int type, char *src, char * src_end) if (!n) return false; memcpy (n, sym, len + 1); - section = bfd_make_section (abfd, n); + section = bfd_make_section_old_way (abfd, n); if (section == NULL) return false; } @@ -406,13 +403,16 @@ first_phase (bfd *abfd, int type, char *src, char * src_end) { case '1': /* Section range. */ src++; - if (!getvalue (&src, §ion->vma, src_end)) + if (!getvalue (&src, &addr, src_end)) return false; if (!getvalue (&src, &val, src_end)) return false; - if (val < section->vma) - val = section->vma; - section->size = val - section->vma; + if (bfd_is_const_section (section)) + break; + section->vma = addr; + if (val < addr) + val = addr; + section->size = val - addr; /* PR 17512: file: objdump-s-endless-loop.tekhex. Check for overlarge section sizes. */ if (section->size & 0x80000000) @@ -455,6 +455,8 @@ first_phase (bfd *abfd, int type, char *src, char * src_end) new_symbol->symbol.flags = BSF_LOCAL; if (stype == '2' || stype == '6') new_symbol->symbol.section = bfd_abs_section_ptr; + else if (bfd_is_const_section (section)) + ; else if (stype == '3' || stype == '7') { if ((section->flags & SEC_DATA) == 0) @@ -719,24 +721,13 @@ writevalue (char **dst, bfd_vma value) int len; int shift; - for (len = 8, shift = 28; shift; shift -= 4, len--) - { - if ((value >> shift) & 0xf) - { - *p++ = len + '0'; - while (len) - { - *p++ = digs[(value >> shift) & 0xf]; - shift -= 4; - len--; - } - *dst = p; - return; + for (len = BFD_ARCH_SIZE / 4, shift = len * 4 - 4; len > 1; shift -= 4, len--) + if ((value >> shift) & 0xf) + break; - } - } - *p++ = '1'; - *p++ = '0'; + *p++ = digs[len & 0xf]; + for (; len; shift -= 4, len--) + *p++ = digs[(value >> shift) & 0xf]; *dst = p; } @@ -747,22 +738,14 @@ writesym (char **dst, const char *sym) int len = (sym ? strlen (sym) : 0); if (len >= 16) + len = 16; + else if (len == 0) { - *p++ = '0'; - len = 16; - } - else - { - if (len == 0) - { - *p++ = '1'; - sym = "$"; - len = 1; - } - else - *p++ = digs[len]; + len = 1; + sym = "$"; } + *p++ = digs[len & 0xf]; while (len--) *p++ = *sym++; diff --git a/bfd/version.h b/bfd/version.h index d02f0d3..cdf4189 100644 --- a/bfd/version.h +++ b/bfd/version.h @@ -16,7 +16,7 @@ In releases, the date is not included in either version strings or sonames. */ -#define BFD_VERSION_DATE 20240803 +#define BFD_VERSION_DATE 20241115 #define BFD_VERSION @bfd_version@ #define BFD_VERSION_STRING @bfd_version_package@ @bfd_version_string@ #define REPORT_BUGS_TO @report_bugs_to@ diff --git a/bfd/vms-alpha.c b/bfd/vms-alpha.c index 6eea61d..df279bc 100644 --- a/bfd/vms-alpha.c +++ b/bfd/vms-alpha.c @@ -8330,18 +8330,26 @@ evax_bfd_print_image (bfd *abfd, FILE *file) } /* xgettext:c-format */ fprintf (file, _("Image identification: (major: %u, minor: %u)\n"), - (unsigned)bfd_getl32 (eihi.majorid), - (unsigned)bfd_getl32 (eihi.minorid)); - fprintf (file, _(" image name : %.*s\n"), - eihi.imgnam[0], eihi.imgnam + 1); + (unsigned) bfd_getl32 (eihi.majorid), + (unsigned) bfd_getl32 (eihi.minorid)); + unsigned int nlen = eihi.imgnam[0]; + if (nlen > sizeof (eihi.imgnam) - 1) + nlen = sizeof (eihi.imgnam) - 1; + fprintf (file, _(" image name : %.*s\n"), nlen, eihi.imgnam + 1); fprintf (file, _(" link time : %s\n"), vms_time_to_str (eihi.linktime)); - fprintf (file, _(" image ident : %.*s\n"), - eihi.imgid[0], eihi.imgid + 1); - fprintf (file, _(" linker ident : %.*s\n"), - eihi.linkid[0], eihi.linkid + 1); - fprintf (file, _(" image build ident: %.*s\n"), - eihi.imgbid[0], eihi.imgbid + 1); + nlen = eihi.imgid[0]; + if (nlen > sizeof (eihi.imgid) - 1) + nlen = sizeof (eihi.imgid) - 1; + fprintf (file, _(" image ident : %.*s\n"), nlen, eihi.imgid + 1); + nlen = eihi.linkid[0]; + if (nlen > sizeof (eihi.linkid) - 1) + nlen = sizeof (eihi.linkid) - 1; + fprintf (file, _(" linker ident : %.*s\n"), nlen, eihi.linkid + 1); + nlen = eihi.imgbid[0]; + if (nlen > sizeof (eihi.imgbid) -1 ) + nlen = sizeof (eihi.imgbid) - 1; + fprintf (file, _(" image build ident: %.*s\n"), nlen, eihi.imgbid + 1); } if (eihs_off != 0) { @@ -8474,10 +8482,15 @@ evax_bfd_print_image (bfd *abfd, FILE *file) } fputs (_(")\n"), file); if (val & EISD__M_GBL) - /* xgettext:c-format */ - fprintf (file, _(" ident: 0x%08x, name: %.*s\n"), - (unsigned)bfd_getl32 (eisd.ident), - eisd.gblnam[0], eisd.gblnam + 1); + { + unsigned int nlen = eisd.gblnam[0]; + if (nlen > sizeof (eisd.gblnam) - 1) + nlen = sizeof (eisd.gblnam) - 1; + /* xgettext:c-format */ + fprintf (file, _(" ident: 0x%08x, name: %.*s\n"), + (unsigned) bfd_getl32 (eisd.ident), + nlen, eisd.gblnam + 1); + } eisd_off += len; } @@ -8628,11 +8641,14 @@ evax_bfd_print_image (bfd *abfd, FILE *file) j++, shlstoff += sizeof (struct vms_shl)) { struct vms_shl *shl = (struct vms_shl *) (buf + shlstoff); + unsigned int nlen = shl->imgnam[0]; + if (nlen > sizeof (shl->imgnam) - 1) + nlen = sizeof (shl->imgnam) - 1; fprintf (file, /* xgettext:c-format */ _(" %u: size: %u, flags: 0x%02x, name: %.*s\n"), j, shl->size, shl->flags, - shl->imgnam[0], shl->imgnam + 1); + nlen, shl->imgnam + 1); } } if (qrelfixoff != 0) |