+
+/* 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;
+ }
+ free (map);
+ return FALSE;
+}
+