-/* This function handles relaxation for 2nd and subsequent passes. */
-
-static boolean
-ip2k_elf_relax_section_passN (abfd, sec, again, final_pass, misc)
- bfd *abfd;
- asection *sec;
- boolean *again;
- boolean *final_pass;
- struct misc * misc;
-{
- Elf_Internal_Rela *irelend = misc->irelbase + sec->reloc_count;
- Elf_Internal_Rela *irel;
- boolean add_all;
-
- /* If we are on the final relaxation pass and the section crosses
- then set a flag to indicate that *all* page instructions need
- to be added back into this section. */
- if (*final_pass)
- {
- add_all = (PAGENO (BASEADDR (sec))
- != PAGENO (BASEADDR (sec) + sec->_cooked_size));
-
- /* If this section crosses a page boundary set the crossed
- page boundary flag. */
- if (add_all)
- sec->userdata = sec;
- else
- {
- /* If the section had previously crossed a page boundary
- but on this pass does not then reset crossed page
- boundary flag and rerun the 1st relaxation pass on
- this section. */
- if (sec->userdata)
- {
- sec->userdata = NULL;
- if (! ip2k_elf_relax_section_pass1 (abfd, sec, again, misc))
- return false;
- }
- }
- }
- else
- add_all = false;
-
- /* Walk thru the section looking for call/jmp
- instructions which need a page instruction. */
- for (irel = misc->irelbase; irel < irelend; irel++)
- {
- if (ELF32_R_TYPE (irel->r_info) == (int) R_IP2K_ADDR16CJP)
- {
- /* Get the value of the symbol referred to by the reloc. */
- bfd_vma symval = symbol_value (abfd, misc->symtab_hdr, misc->isymbuf,
- irel);
- bfd_byte code0, code1;
-
- if (symval == UNDEFINED_SYMBOL)
- {
- /* This appears to be a reference to an undefined
- symbol. Just ignore it--it will be caught by the
- regular reloc processing. */
- continue;
- }
-
- /* For simplicity of coding, we are going to modify the section
- contents, the section relocs, and the BFD symbol table. We
- must tell the rest of the code not to free up this
- information. It would be possible to instead create a table
- of changes which have to be made, as is done in coff-mips.c;
- that would be more work, but would require less memory when
- the linker is run. */
-
- /* Get the opcode. */
- code0 = bfd_get_8 (abfd, misc->contents + irel->r_offset);
- code1 = bfd_get_8 (abfd, misc->contents + irel->r_offset + 1);
-
- if (IS_JMP_OPCODE (code0, code1) || IS_CALL_OPCODE (code0, code1))
- {
- if (*final_pass)
- {
- if (! unrelax_switch_dispatch_tables_passN (abfd, sec,
- irel->r_offset,
- again, misc))
- return false;
-
- if (*again)
- add_all = false;
- }
-
- code0 = bfd_get_8 (abfd, misc->contents + irel->r_offset - 2);
- code1 = bfd_get_8 (abfd, misc->contents + irel->r_offset - 1);
-
- if (! IS_PAGE_OPCODE (code0, code1))
- {
- bfd_vma value = symval + irel->r_addend;
- bfd_vma addr = BASEADDR (sec) + irel->r_offset;
-
- if (add_all || PAGENO (addr) != PAGENO (value))
- {
- if (! add_page_insn (abfd, sec, irel, misc))
- return false;
-
- /* That will have changed things, so, we must relax again. */
- *again = true;
- }
- }
- }
- }
- }
-
- /* If anything changed reset the final pass flag. */
- if (*again)
- *final_pass = false;
-
- return true;
-}
-
-/* Parts of a Stabs entry. */
-
-#define STRDXOFF (0)
-#define TYPEOFF (4)
-#define OTHEROFF (5)
-#define DESCOFF (6)
-#define VALOFF (8)
-#define STABSIZE (12)
-
-/* Adjust all the relocations entries after adding or inserting instructions. */
-
-static void
-adjust_all_relocations (abfd, sec, addr, endaddr, count, noadj)
- bfd *abfd;
- asection *sec;
- bfd_vma addr;
- bfd_vma endaddr;
- int count;
- int noadj;
-{
- Elf_Internal_Shdr *symtab_hdr;
- Elf_Internal_Sym *isymbuf, *isym, *isymend;
- unsigned int shndx;
- bfd_byte *contents;
- Elf_Internal_Rela *irel, *irelend, *irelbase;
- struct elf_link_hash_entry **sym_hashes;
- struct elf_link_hash_entry **end_hashes;
- unsigned int symcount;
-
- symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
- isymbuf = (Elf32_Internal_Sym *) symtab_hdr->contents;
-
- shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
-
- contents = elf_section_data (sec)->this_hdr.contents;
-
- irelbase = elf_section_data (sec)->relocs;
- irelend = irelbase + sec->reloc_count;
-
- for (irel = irelbase; irel < irelend; irel++)
- {
- if (ELF32_R_TYPE (irel->r_info) != R_IP2K_NONE)
- {
- /* Get the value of the symbol referred to by the reloc. */
- if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
- {
- asection *sym_sec;
-
- /* A local symbol. */
- isym = isymbuf + ELF32_R_SYM (irel->r_info);
- sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
-
- if (isym->st_shndx == shndx)
- {
- bfd_vma baseaddr = BASEADDR (sec);
- bfd_vma symval = BASEADDR (sym_sec) + isym->st_value
- + irel->r_addend;
-
- if ((baseaddr + addr + noadj) <= symval
- && symval < (baseaddr + endaddr))
- irel->r_addend += count;
- }
- }
- }
-
- /* Do this only for PC space relocations. */
- if (addr <= irel->r_offset && irel->r_offset < endaddr)
- irel->r_offset += count;
- }
-
- /* When adding an instruction back it is sometimes necessary to move any
- global or local symbol that was referencing the first instruction of
- the moved block to refer to the first instruction of the inserted block.
-
- For example adding a PAGE instruction before a CALL or JMP requires
- that any label on the CALL or JMP is moved to the PAGE insn. */
- addr += noadj;
-
- /* Adjust the local symbols defined in this section. */
- isymend = isymbuf + symtab_hdr->sh_info;
- for (isym = isymbuf; isym < isymend; isym++)
- {
- if (isym->st_shndx == shndx
- && addr <= isym->st_value
- && isym->st_value < endaddr)
- isym->st_value += count;
- }
-
- /* Now adjust the global symbols defined in this section. */
- symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
- - symtab_hdr->sh_info);
- sym_hashes = elf_sym_hashes (abfd);
- end_hashes = sym_hashes + symcount;
- for (; sym_hashes < end_hashes; sym_hashes++)
- {
- struct elf_link_hash_entry *sym_hash = *sym_hashes;
- if ((sym_hash->root.type == bfd_link_hash_defined
- || sym_hash->root.type == bfd_link_hash_defweak)
- && sym_hash->root.u.def.section == sec)
- {
- if (addr <= sym_hash->root.u.def.value
- && sym_hash->root.u.def.value < endaddr)
- {
- sym_hash->root.u.def.value += count;
- }
- }
- }
-
- return;
-}
-
-static boolean
-add_page_insn (abfd, sec, irel, misc)
- bfd *abfd;
- asection *sec;
- Elf_Internal_Rela *irel;
- struct misc *misc;
-{
- /* Note that we've changed the relocs, section contents, etc. */
- elf_section_data (sec)->relocs = misc->irelbase;
- elf_section_data (sec)->this_hdr.contents = misc->contents;
- misc->symtab_hdr->contents = (bfd_byte *) misc->isymbuf;
-
- /* Add the PAGE insn. */
- if (! ip2k_elf_relax_add_bytes (abfd, sec, irel->r_offset,
- page_opcode,
- sizeof (page_opcode),
- sizeof (page_opcode)))
- return false;
- else
- {
- Elf32_Internal_Rela * jrel = irel - 1;
-
- /* Add relocation for PAGE insn added. */
- if (ELF32_R_TYPE (jrel->r_info) != R_IP2K_NONE)
- {
- bfd_byte code0, code1;
- char *msg = NULL;
-
- /* Get the opcode. */
- code0 = bfd_get_8 (abfd, misc->contents + irel->r_offset);
- code1 = bfd_get_8 (abfd, misc->contents + irel->r_offset + 1);
-
- if (IS_JMP_OPCODE (code0, code1))
- msg = "\tJMP instruction missing a preceeding PAGE instruction in %s\n\n";
-
- else if (IS_CALL_OPCODE (code0, code1))
- msg = "\tCALL instruction missing a preceeding PAGE instruction in %s\n\n";
-
- if (msg)
- {
- fprintf (stderr, "\n\t *** LINKER RELAXATION failure ***\n");
- fprintf (stderr, msg, sec->owner->filename);
- }
-
- return false;
- }
-
- jrel->r_addend = irel->r_addend;
- jrel->r_offset = irel->r_offset - sizeof (page_opcode);
- jrel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
- R_IP2K_PAGE3);
- }
-
- return true;
-}
-
-/* Insert bytes into a section while relaxing. */
-
-static boolean
-ip2k_elf_relax_add_bytes (abfd, sec, addr, bytes, count, noadj)
- bfd *abfd;
- asection *sec;
- bfd_vma addr;
- const bfd_byte *bytes;
- int count;
- int noadj;
-{
- bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
- bfd_vma endaddr = sec->_cooked_size;
-
- /* Make room to insert the bytes. */
- memmove (contents + addr + count, contents + addr, endaddr - addr);
-
- /* Insert the bytes into the section. */
- memcpy (contents + addr, bytes, count);
-
- sec->_cooked_size += count;
-
- adjust_all_relocations (abfd, sec, addr, endaddr, count, noadj);
- return true;
-}
-
-/* Delete some bytes from a section while relaxing. */
-
-static boolean
-ip2k_elf_relax_delete_bytes (abfd, sec, addr, count)
- bfd *abfd;
- asection *sec;
- bfd_vma addr;
- int count;
-{
- bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
- bfd_vma endaddr = sec->_cooked_size;
-
- /* Actually delete the bytes. */
- memmove (contents + addr, contents + addr + count,
- endaddr - addr - count);
-
- sec->_cooked_size -= count;
-
- adjust_all_relocations (abfd, sec, addr + count, endaddr, -count, 0);
- return true;
-}
-
-/* -------------------------------------------------------------------- */
-
-/* XXX: The following code is the result of a cut&paste. This unfortunate
- practice is very widespread in the various target back-end files. */
-