📄 elf32-mips.c
字号:
reloc_entry->addend = relocation - 4; } /* Now do the LO16 reloc in the usual way. */ return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd, error_message);}/* Do a R_MIPS_GOT16 reloc. This is a reloc against the global offset table used for PIC code. If the symbol is an external symbol, the instruction is modified to contain the offset of the appropriate entry in the global offset table. If the symbol is a section symbol, the next reloc is a R_MIPS_LO16 reloc. The two 16 bit addends are combined to form the real addend against the section symbol; the GOT16 is modified to contain the offset of an entry in the global offset table, and the LO16 is modified to offset it appropriately. Thus an offset larger than 16 bits requires a modified value in the global offset table. This implementation suffices for the assembler, but the linker does not yet know how to create global offset tables. */bfd_reloc_status_type_bfd_mips_elf_got16_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd, error_message) bfd *abfd; arelent *reloc_entry; asymbol *symbol; PTR data; asection *input_section; bfd *output_bfd; char **error_message;{ /* If we're relocating, and this an external symbol, we don't want to change anything. */ if (output_bfd != (bfd *) NULL && (symbol->flags & BSF_SECTION_SYM) == 0 && reloc_entry->addend == 0) { reloc_entry->address += input_section->output_offset; return bfd_reloc_ok; } /* If we're relocating, and this is a local symbol, we can handle it just like HI16. */ if (output_bfd != (bfd *) NULL && (symbol->flags & BSF_SECTION_SYM) != 0) return _bfd_mips_elf_hi16_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd, error_message); abort ();}/* Set the GP value for OUTPUT_BFD. Returns false if this is a dangerous relocation. */static booleanmips_elf_assign_gp (output_bfd, pgp) bfd *output_bfd; bfd_vma *pgp;{ unsigned int count; asymbol **sym; unsigned int i; /* If we've already figured out what GP will be, just return it. */ *pgp = _bfd_get_gp_value (output_bfd); if (*pgp) return true; count = bfd_get_symcount (output_bfd); sym = bfd_get_outsymbols (output_bfd); /* The linker script will have created a symbol named `_gp' with the appropriate value. */ if (sym == (asymbol **) NULL) i = count; else { for (i = 0; i < count; i++, sym++) { register CONST char *name; name = bfd_asymbol_name (*sym); if (*name == '_' && strcmp (name, "_gp") == 0) { *pgp = bfd_asymbol_value (*sym); _bfd_set_gp_value (output_bfd, *pgp); break; } } } if (i >= count) { /* Only get the error once. */ *pgp = 4; _bfd_set_gp_value (output_bfd, *pgp); return false; } return true;}/* We have to figure out the gp value, so that we can adjust the symbol value correctly. We look up the symbol _gp in the output BFD. If we can't find it, we're stuck. We cache it in the ELF target data. We don't need to adjust the symbol value for an external symbol if we are producing relocateable output. */static bfd_reloc_status_typemips_elf_final_gp (output_bfd, symbol, relocateable, error_message, pgp) bfd *output_bfd; asymbol *symbol; boolean relocateable; char **error_message; bfd_vma *pgp;{ if (bfd_is_und_section (symbol->section) && ! relocateable) { *pgp = 0; return bfd_reloc_undefined; } *pgp = _bfd_get_gp_value (output_bfd); if (*pgp == 0 && (! relocateable || (symbol->flags & BSF_SECTION_SYM) != 0)) { if (relocateable) { /* Make up a value. */ *pgp = symbol->section->output_section->vma + 0x4000; _bfd_set_gp_value (output_bfd, *pgp); } else if (!mips_elf_assign_gp (output_bfd, pgp)) { *error_message = (char *) _("GP relative relocation when _gp not defined"); return bfd_reloc_dangerous; } } return bfd_reloc_ok;}/* Do a R_MIPS_GPREL16 relocation. This is a 16 bit value which must become the offset from the gp register. This function also handles R_MIPS_LITERAL relocations, although those can be handled more cleverly because the entries in the .lit8 and .lit4 sections can be merged. */static bfd_reloc_status_type gprel16_with_gp PARAMS ((bfd *, asymbol *, arelent *, asection *, boolean, PTR, bfd_vma));bfd_reloc_status_type_bfd_mips_elf_gprel16_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd, error_message) bfd *abfd; arelent *reloc_entry; asymbol *symbol; PTR data; asection *input_section; bfd *output_bfd; char **error_message;{ boolean relocateable; bfd_reloc_status_type ret; bfd_vma gp; /* If we're relocating, and this is an external symbol with no addend, we don't want to change anything. We will only have an addend if this is a newly created reloc, not read from an ELF file. */ if (output_bfd != (bfd *) NULL && (symbol->flags & BSF_SECTION_SYM) == 0 && reloc_entry->addend == 0) { reloc_entry->address += input_section->output_offset; return bfd_reloc_ok; } if (output_bfd != (bfd *) NULL) relocateable = true; else { relocateable = false; output_bfd = symbol->section->output_section->owner; } ret = mips_elf_final_gp (output_bfd, symbol, relocateable, error_message, &gp); if (ret != bfd_reloc_ok) return ret; return gprel16_with_gp (abfd, symbol, reloc_entry, input_section, relocateable, data, gp);}static bfd_reloc_status_typegprel16_with_gp (abfd, symbol, reloc_entry, input_section, relocateable, data, gp) bfd *abfd; asymbol *symbol; arelent *reloc_entry; asection *input_section; boolean relocateable; PTR data; bfd_vma gp;{ bfd_vma relocation; unsigned long insn; unsigned long val; if (bfd_is_com_section (symbol->section)) relocation = 0; else relocation = symbol->value; relocation += symbol->section->output_section->vma; relocation += symbol->section->output_offset; if (reloc_entry->address > input_section->_cooked_size) return bfd_reloc_outofrange; insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); /* Set val to the offset into the section or symbol. */ if (reloc_entry->howto->src_mask == 0) { /* This case occurs with the 64-bit MIPS ELF ABI. */ val = reloc_entry->addend; } else { val = ((insn & 0xffff) + reloc_entry->addend) & 0xffff; if (val & 0x8000) val -= 0x10000; } /* Adjust val for the final section location and GP value. If we are producing relocateable output, we don't want to do this for an external symbol. */ if (! relocateable || (symbol->flags & BSF_SECTION_SYM) != 0) val += relocation - gp; insn = (insn & ~0xffff) | (val & 0xffff); bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address); if (relocateable) reloc_entry->address += input_section->output_offset; /* Make sure it fit in 16 bits. */ if ((long) val >= 0x8000 || (long) val < -0x8000) return bfd_reloc_overflow; return bfd_reloc_ok;}/* Do a R_MIPS_GPREL32 relocation. Is this 32 bit value the offset from the gp register? XXX */static bfd_reloc_status_type gprel32_with_gp PARAMS ((bfd *, asymbol *, arelent *, asection *, boolean, PTR, bfd_vma));bfd_reloc_status_type_bfd_mips_elf_gprel32_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd, error_message) bfd *abfd; arelent *reloc_entry; asymbol *symbol; PTR data; asection *input_section; bfd *output_bfd; char **error_message;{ boolean relocateable; bfd_reloc_status_type ret; bfd_vma gp; /* If we're relocating, and this is an external symbol with no addend, we don't want to change anything. We will only have an addend if this is a newly created reloc, not read from an ELF file. */ if (output_bfd != (bfd *) NULL && (symbol->flags & BSF_SECTION_SYM) == 0 && reloc_entry->addend == 0) { *error_message = (char *) _("32bits gp relative relocation occurs for an external symbol"); return bfd_reloc_outofrange; } if (output_bfd != (bfd *) NULL) { relocateable = true; gp = _bfd_get_gp_value (output_bfd); } else { relocateable = false; output_bfd = symbol->section->output_section->owner; ret = mips_elf_final_gp (output_bfd, symbol, relocateable, error_message, &gp); if (ret != bfd_reloc_ok) return ret; } return gprel32_with_gp (abfd, symbol, reloc_entry, input_section, relocateable, data, gp);}static bfd_reloc_status_typegprel32_with_gp (abfd, symbol, reloc_entry, input_section, relocateable, data, gp) bfd *abfd; asymbol *symbol; arelent *reloc_entry; asection *input_section; boolean relocateable; PTR data; bfd_vma gp;{ bfd_vma relocation; unsigned long val; if (bfd_is_com_section (symbol->section)) relocation = 0; else relocation = symbol->value; relocation += symbol->section->output_section->vma; relocation += symbol->section->output_offset; if (reloc_entry->address > input_section->_cooked_size) return bfd_reloc_outofrange; if (reloc_entry->howto->src_mask == 0) { /* This case arises with the 64-bit MIPS ELF ABI. */ val = 0; } else val = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); /* Set val to the offset into the section or symbol. */ val += reloc_entry->addend; /* Adjust val for the final section location and GP value. If we are producing relocateable output, we don't want to do this for an external symbol. */ if (! relocateable || (symbol->flags & BSF_SECTION_SYM) != 0) val += relocation - gp; bfd_put_32 (abfd, val, (bfd_byte *) data + reloc_entry->address); if (relocateable) reloc_entry->address += input_section->output_offset; return bfd_reloc_ok;}/* Handle a 64 bit reloc in a 32 bit MIPS ELF file. These are generated when addresses are 64 bits. The upper 32 bits are a simple sign extension. */static bfd_reloc_status_typemips32_64bit_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd, error_message) bfd *abfd; arelent *reloc_entry; asymbol *symbol; PTR data; asection *input_section; bfd *output_bfd; char **error_message;{ bfd_reloc_status_type r; arelent reloc32; unsigned long val; bfd_size_type addr; r = bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd, error_message); if (r != bfd_reloc_continue) return r; /* Do a normal 32 bit relocation on the lower 32 bits. */ reloc32 = *reloc_entry; if (bfd_big_endian (abfd)) reloc32.address += 4; reloc32.howto = &elf_mips_howto_table[R_MIPS_32]; r = bfd_perform_relocation (abfd, &reloc32, data, input_section, output_bfd, error_message); /* Sign extend into the upper 32 bits. */ val = bfd_get_32 (abfd, (bfd_byte *) data + reloc32.address); if ((val & 0x80000000) != 0) val = 0xffffffff; else val = 0; addr = reloc_entry->address; if (bfd_little_endian (abfd)) addr += 4; bfd_put_32 (abfd, val, (bfd_byte *) data + addr); return r;}/* Handle a mips16 jump. */static bfd_reloc_status_typemips16_jump_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd, error_message)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -