diff options
author | Paul Brook <paul@codesourcery.com> | 2004-04-01 11:20:04 +0000 |
---|---|---|
committer | Paul Brook <paul@codesourcery.com> | 2004-04-01 11:20:04 +0000 |
commit | e489d0aef709443ce63e0bb21e7eb18c9575d35c (patch) | |
tree | 11d092a8131778662a15eb101fb53e8f673ea4b2 /bfd/elf32-arm.h | |
parent | 935a41f543c3804fbf438d070234570cf8b03076 (diff) | |
download | gdb-e489d0aef709443ce63e0bb21e7eb18c9575d35c.zip gdb-e489d0aef709443ce63e0bb21e7eb18c9575d35c.tar.gz gdb-e489d0aef709443ce63e0bb21e7eb18c9575d35c.tar.bz2 |
* bfd/bfd-in.h (bfd_elf32_arm_process_before_allocation): Update.
* bfd/elf32-arm.h (struct elf32_elf_section_map): New.
(struct _arm_elf_section_data): New.
(elf32_arm_section_data): Define.
(struct elf32_arm_link_hash_table): Add byteswap_code.
(elf32_arm_link_hash_table_create): Initialize byteswap_code.
(bfd_elf32_arm_process_before_allocation): Add byteswap_code.
(elf32_arm_post_process_headers): Set EF_ARM_BE8.
(elf32_arm_output_symbol_hook, elf32_arm_new_section_hook,
elf32_arm_compare_mapping, elf32_arm_write_section): New functions.
(bfd_elf32_new_section_hook, elf_backend_write_section,
elf_backend_link_output_symbol_hook): Define.
* ld/emultempl/armelf.em (byteswap_code): Add.
(arm_elf_before_allocation): Pass extra parameter.
(PARSE_AND_LIST_PROLOGUE): Add OPTION_BE8.
(PARSE_AND_LIST_LONGOPTS, PARSE_AND_LIST_OPTIONS): Add be8.
(PARSE_AND_LIST_ARGS_CASES): Handle OPTION_BE8.
* ld/emultempl/armelf_oabi.em: Pass extra parameter.
* ld/ld.texinfo: Document --be8.
Diffstat (limited to 'bfd/elf32-arm.h')
-rw-r--r-- | bfd/elf32-arm.h | 191 |
1 files changed, 188 insertions, 3 deletions
diff --git a/bfd/elf32-arm.h b/bfd/elf32-arm.h index bc6904a..b9e3deb 100644 --- a/bfd/elf32-arm.h +++ b/bfd/elf32-arm.h @@ -106,7 +106,7 @@ bfd_boolean bfd_elf32_arm_allocate_interworking_sections bfd_boolean bfd_elf32_arm_get_bfd_for_interworking PARAMS ((bfd *, struct bfd_link_info *)); bfd_boolean bfd_elf32_arm_process_before_allocation - PARAMS ((bfd *, struct bfd_link_info *, int)); + PARAMS ((bfd *, struct bfd_link_info *, int, int)); #endif @@ -190,6 +190,26 @@ static const bfd_vma elf32_arm_plt_entry [PLT_ENTRY_SIZE / 4] = #endif +/* Used to build a map of a section. This is required for mixed-endian + code/data. */ + +typedef struct elf32_elf_section_map +{ + bfd_vma vma; + char type; +} +elf32_arm_section_map; + +struct _arm_elf_section_data +{ + struct bfd_elf_section_data elf; + int mapcount; + elf32_arm_section_map *map; +}; + +#define elf32_arm_section_data(sec) \ + ((struct _arm_elf_section_data *) elf_section_data (sec)) + /* The ARM linker needs to keep track of the number of relocs that it decides to copy in check_relocs for each symbol. This is so that it can discard PC relative relocs if it doesn't need them when @@ -247,6 +267,9 @@ struct elf32_arm_link_hash_table length should be applied by the linker. */ int no_pipeline_knowledge; + /* Nonzero to output a BE8 image. */ + int byteswap_code; + /* Short-cuts to get to dynamic linker sections. */ asection *sgot; asection *sgotplt; @@ -430,6 +453,7 @@ elf32_arm_link_hash_table_create (abfd) ret->arm_glue_size = 0; ret->bfd_of_glue_owner = NULL; ret->no_pipeline_knowledge = 0; + ret->byteswap_code = 0; ret->sym_sec.abfd = NULL; return &ret->root.root; @@ -808,10 +832,13 @@ bfd_elf32_arm_get_bfd_for_interworking (abfd, info) } bfd_boolean -bfd_elf32_arm_process_before_allocation (abfd, link_info, no_pipeline_knowledge) +bfd_elf32_arm_process_before_allocation (abfd, link_info, + no_pipeline_knowledge, + byteswap_code) bfd *abfd; struct bfd_link_info *link_info; int no_pipeline_knowledge; + int byteswap_code; { Elf_Internal_Shdr *symtab_hdr; Elf_Internal_Rela *internal_relocs = NULL; @@ -834,6 +861,14 @@ bfd_elf32_arm_process_before_allocation (abfd, link_info, no_pipeline_knowledge) BFD_ASSERT (globals->bfd_of_glue_owner != NULL); globals->no_pipeline_knowledge = no_pipeline_knowledge; + if (byteswap_code && !bfd_big_endian (abfd)) + { + _bfd_error_handler ( + _("%s: BE8 images only valid in big-endian mode."), + bfd_archive_filename (abfd)); + return FALSE; + } + globals->byteswap_code = byteswap_code; /* Rummage around all the relocs and map the glue vectors. */ sec = abfd->sections; @@ -4049,11 +4084,16 @@ elf32_arm_post_process_headers (abfd, link_info) struct bfd_link_info * link_info ATTRIBUTE_UNUSED; { Elf_Internal_Ehdr * i_ehdrp; /* ELF file header, internal form. */ + struct elf32_arm_link_hash_table *globals; i_ehdrp = elf_elfheader (abfd); i_ehdrp->e_ident[EI_OSABI] = ARM_ELF_OS_ABI_VERSION; i_ehdrp->e_ident[EI_ABIVERSION] = ARM_ELF_ABI_VERSION; + + globals = elf32_arm_hash_table (link_info); + if (globals->byteswap_code) + i_ehdrp->e_flags |= EF_ARM_BE8; } static enum elf_reloc_type_class @@ -4089,7 +4129,7 @@ elf32_arm_section_flags (flags, hdr) return TRUE; } -void +static void elf32_arm_final_write_processing (abfd, linker) bfd *abfd; bfd_boolean linker ATTRIBUTE_UNUSED; @@ -4097,6 +4137,148 @@ elf32_arm_final_write_processing (abfd, linker) bfd_arm_update_notes (abfd, ARM_NOTE_SECTION); } + +/* Called for each symbol. Builds a section map based on mapping symbols. + Does not alter any of the symbols. */ + +static bfd_boolean +elf32_arm_output_symbol_hook (struct bfd_link_info *info, + const char *name, + Elf_Internal_Sym *elfsym, + asection *input_sec, + struct elf_link_hash_entry *h ATTRIBUTE_UNUSED) +{ + int mapcount; + elf32_arm_section_map *map; + struct elf32_arm_link_hash_table *globals; + + /* Only do this on final link. */ + if (info->relocatable) + return TRUE; + + /* Only build a map if we need to byteswap code. */ + globals = elf32_arm_hash_table (info); + if (!globals->byteswap_code) + return TRUE; + + /* We only want mapping symbols. */ + if (name == NULL + || name[0] != '$' + || (name[1] != 'a' + && name[1] != 't' + && name[1] != 'd')) + return TRUE; + + mapcount = ++(elf32_arm_section_data (input_sec)->mapcount); + map = elf32_arm_section_data (input_sec)->map; + /* TODO: This may be inefficient, but we probably don't usually have many + mapping symbols per section. */ + map = bfd_realloc (map, mapcount * sizeof (elf32_arm_section_map)); + elf32_arm_section_data (input_sec)->map = map; + + map[mapcount - 1].vma = elfsym->st_value; + map[mapcount - 1].type = name[1]; + return TRUE; +} + + +/* Allocate target specific section data. */ + +static bfd_boolean +elf32_arm_new_section_hook (bfd *abfd, asection *sec) +{ + struct _arm_elf_section_data *sdata; + bfd_size_type amt = sizeof (*sdata); + + sdata = bfd_zalloc (abfd, amt); + if (sdata == NULL) + return FALSE; + sec->used_by_bfd = sdata; + + return _bfd_elf_new_section_hook (abfd, sec); +} + + +/* Used to order a list of mapping symbols by address. */ + +static int +elf32_arm_compare_mapping (const void * a, const void * b) +{ + return ((const elf32_arm_section_map *) a)->vma + > ((const elf32_arm_section_map *) b)->vma; +} + + +/* Do code byteswapping. Return FALSE afterwards so that the section is + written out as normal. */ + +static bfd_boolean +elf32_arm_write_section (bfd *output_bfd ATTRIBUTE_UNUSED, asection *sec, + bfd_byte *contents) +{ + int mapcount; + elf32_arm_section_map *map; + bfd_vma ptr; + bfd_vma end; + bfd_vma offset; + bfd_byte tmp; + int i; + + mapcount = elf32_arm_section_data (sec)->mapcount; + map = elf32_arm_section_data (sec)->map; + + if (mapcount == 0) + return FALSE; + + qsort (map, mapcount, sizeof (elf32_arm_section_map), + elf32_arm_compare_mapping); + + offset = sec->output_section->vma + sec->output_offset; + ptr = map[0].vma - offset; + for (i = 0; i < mapcount; i++) + { + if (i == mapcount - 1) + end = bfd_section_size (output_bfd, sec); + else + end = map[i + 1].vma - offset; + + switch (map[i].type) + { + case 'a': + /* Byte swap code words. */ + while (ptr + 3 < end) + { + tmp = contents[ptr]; + contents[ptr] = contents[ptr + 3]; + contents[ptr + 3] = tmp; + tmp = contents[ptr + 1]; + contents[ptr + 1] = contents[ptr + 2]; + contents[ptr + 2] = tmp; + ptr += 4; + } + break; + + case 't': + /* Byte swap code halfwords. */ + while (ptr + 1 < end) + { + tmp = contents[ptr]; + contents[ptr] = contents[ptr + 1]; + contents[ptr + 1] = tmp; + ptr += 2; + } + break; + + case 'd': + /* Leave data alone. */ + break; + } + ptr = end; + } + bfd_free (map); + return FALSE; +} + #define ELF_ARCH bfd_arch_arm #define ELF_MACHINE_CODE EM_ARM #ifdef __QNXTARGET__ @@ -4112,16 +4294,19 @@ elf32_arm_final_write_processing (abfd, linker) #define bfd_elf32_bfd_link_hash_table_create elf32_arm_link_hash_table_create #define bfd_elf32_bfd_reloc_type_lookup elf32_arm_reloc_type_lookup #define bfd_elf32_find_nearest_line elf32_arm_find_nearest_line +#define bfd_elf32_new_section_hook elf32_arm_new_section_hook #define elf_backend_get_symbol_type elf32_arm_get_symbol_type #define elf_backend_gc_mark_hook elf32_arm_gc_mark_hook #define elf_backend_gc_sweep_hook elf32_arm_gc_sweep_hook #define elf_backend_check_relocs elf32_arm_check_relocs #define elf_backend_relocate_section elf32_arm_relocate_section +#define elf_backend_write_section elf32_arm_write_section #define elf_backend_adjust_dynamic_symbol elf32_arm_adjust_dynamic_symbol #define elf_backend_create_dynamic_sections elf32_arm_create_dynamic_sections #define elf_backend_finish_dynamic_symbol elf32_arm_finish_dynamic_symbol #define elf_backend_finish_dynamic_sections elf32_arm_finish_dynamic_sections +#define elf_backend_link_output_symbol_hook elf32_arm_output_symbol_hook #define elf_backend_size_dynamic_sections elf32_arm_size_dynamic_sections #define elf_backend_post_process_headers elf32_arm_post_process_headers #define elf_backend_reloc_type_class elf32_arm_reloc_type_class |