#ifdef SHLIB
#include "shlib.h"
#endif
#include <stdlib.h>
#if !(defined(KLD) && defined(__STATIC__))
#include <stdio.h>
#include <mach/mach.h>
#else
#include <mach/kern_return.h>
#endif
#include <string.h>
#include <stdarg.h>
#include <mach-o/loader.h>
#include <mach-o/reloc.h>
#include <mach-o/hppa/reloc.h>
#include <mach-o/nlist.h>
#include "stuff/bool.h"
#include "stuff/bytesex.h"
#include "stuff/hppa.h"
#include "ld.h"
#include "live_refs.h"
#include "objects.h"
#include "sections.h"
#include "pass1.h"
#include "symbols.h"
#include "pass2.h"
#include "generic_reloc.h"
#include "hppa_reloc.h"
#include "indirect_sections.h"
#include "dylibs.h"
#define U_ABS(l) (((long)(l))<0 ? (unsigned long)(-(l)) : (l))
__private_extern__
void
hppa_reloc(
char *contents,
struct relocation_info *relocs,
struct section_map *section_map)
{
unsigned long i, j, symbolnum, value, input_pc, output_pc;
unsigned long instruction, immediate;
struct nlist *nlists;
char *strings;
enum bool force_extern_reloc;
struct undefined_map *undefined_map;
struct merged_symbol *merged_symbol;
struct section_map *local_map, *pair_local_map;
struct relocation_info *reloc, *pair_reloc;
struct scattered_relocation_info *sreloc, *spair_reloc;
unsigned long r_address, r_symbolnum, r_pcrel, r_length, r_extern,
r_scattered, r_value, pair_r_symbolnum, pair_r_value;
enum reloc_type_hppa r_type, pair_r_type;
unsigned long other_half;
unsigned long offset;
uint32_t hi21, lo14;
uint32_t w, w1, w2;
#if defined(DEBUG) || defined(RLD)
merged_symbol = NULL;
local_map = NULL;
instruction = 0;
other_half = 0;
immediate = 0;
offset = 0;
pair_r_symbolnum = 0;
pair_r_value = 0;
pair_local_map = NULL;
#endif
for(i = 0; i < section_map->s->nreloc; i++){
force_extern_reloc = FALSE;
if((relocs[i].r_address & R_SCATTERED) != 0){
sreloc = (struct scattered_relocation_info *)(relocs + i);
reloc = NULL;
r_scattered = 1;
r_address = sreloc->r_address;
r_pcrel = sreloc->r_pcrel;
r_length = sreloc->r_length;
r_value = sreloc->r_value;
r_type = (enum reloc_type_hppa)sreloc->r_type;
r_extern = 0;
if(r_type == HPPA_RELOC_PAIR){
error_with_cur_obj("stray relocation HPPA_RELOC_PAIR entry "
"(%lu) in section (%.16s,%.16s)", i,
section_map->s->segname, section_map->s->sectname);
continue;
}
r_symbolnum = 0;
for(j = 0; j < cur_obj->nsection_maps; j++){
if(r_value >= cur_obj->section_maps[j].s->addr &&
r_value < cur_obj->section_maps[j].s->addr +
cur_obj->section_maps[j].s->size){
r_symbolnum = j + 1;
break;
}
}
if(r_symbolnum == 0){
for(j = 0; j < cur_obj->nsection_maps; j++){
if(r_value == cur_obj->section_maps[j].s->addr +
cur_obj->section_maps[j].s->size){
r_symbolnum = j + 1;
break;
}
}
if(r_symbolnum == 0){
error_with_cur_obj("r_value (0x%x) field of relocation "
"entry %lu in section (%.16s,%.16s) out of range",
(unsigned int)r_value, i, section_map->s->segname,
section_map->s->sectname);
return;
}
}
}
else{
reloc = relocs + i;
sreloc = NULL;
r_scattered = 0;
r_address = reloc->r_address;
r_pcrel = reloc->r_pcrel;
r_length = reloc->r_length;
r_extern = reloc->r_extern;
r_symbolnum = reloc->r_symbolnum;
r_type = (enum reloc_type_hppa)reloc->r_type;
r_value = 0;
}
if(r_type == HPPA_RELOC_PAIR){
error_with_cur_obj("stray relocation HPPA_RELOC_PAIR entry "
"(%lu) in section (%.16s,%.16s)", i,
section_map->s->segname, section_map->s->sectname);
continue;
}
if(r_address >= section_map->s->size){
error_with_cur_obj("r_address (0x%x) field of relocation entry "
"%lu in section (%.16s,%.16s) out of range",
(unsigned int)r_address, i, section_map->s->segname,
section_map->s->sectname);
return;
}
pair_r_type = (enum reloc_type_hppa)0;
pair_reloc = NULL;
spair_reloc = NULL;
if(r_type == HPPA_RELOC_HI21 || r_type == HPPA_RELOC_LO14 ||
r_type == HPPA_RELOC_BR17 || r_type == HPPA_RELOC_JBSR) {
if(i + 1 < section_map->s->nreloc){
pair_reloc = relocs + i + 1;
if((pair_reloc->r_address & R_SCATTERED) != 0){
spair_reloc = (struct scattered_relocation_info *)
pair_reloc;
pair_reloc = NULL;
pair_r_type = (enum reloc_type_hppa)spair_reloc->r_type;
other_half = spair_reloc->r_address;
}
else{
pair_r_type = (enum reloc_type_hppa)pair_reloc->r_type;
other_half = pair_reloc->r_address;
}
}
if((pair_reloc == NULL && spair_reloc == NULL) ||
pair_r_type != HPPA_RELOC_PAIR){
error_with_cur_obj("relocation entry (%lu) in section "
"(%.16s,%.16s) missing following associated "
"HPPA_RELOC_PAIR entry", i, section_map->s->segname,
section_map->s->sectname);
continue;
}
}
else if(r_type == HPPA_RELOC_SECTDIFF ||
r_type == HPPA_RELOC_HI21_SECTDIFF ||
r_type == HPPA_RELOC_LO14_SECTDIFF){
if(r_scattered != 1){
error_with_cur_obj("relocation entry (%lu) in section "
"(%.16s,%.16s) r_type is HPPA_RELOC_SECTDIFF but "
"relocation entry not scattered type", i,
section_map->s->segname, section_map->s->sectname);
continue;
}
if(i + 1 < section_map->s->nreloc){
pair_reloc = relocs + i + 1;
if((pair_reloc->r_address & R_SCATTERED) != 0){
spair_reloc = (struct scattered_relocation_info *)
pair_reloc;
pair_reloc = NULL;
pair_r_type = (enum reloc_type_hppa)spair_reloc->r_type;
pair_r_value = spair_reloc->r_value;
other_half = spair_reloc->r_address;
}
else{
error_with_cur_obj("relocation entry (%lu) in section "
"(%.16s,%.16s) following associated relocation "
"entry not scattered type", i,
section_map->s->segname, section_map->s->sectname);
continue;
}
}
if((pair_reloc == NULL && spair_reloc == NULL) ||
pair_r_type != HPPA_RELOC_PAIR){
error_with_cur_obj("relocation entry (%lu) in section "
"(%.16s,%.16s) missing following associated "
"HPPA_RELOC_PAIR entry", i, section_map->s->segname,
section_map->s->sectname);
continue;
}
pair_r_symbolnum = 0;
for(j = 0; j < cur_obj->nsection_maps; j++){
if(pair_r_value >= cur_obj->section_maps[j].s->addr &&
pair_r_value < cur_obj->section_maps[j].s->addr +
cur_obj->section_maps[j].s->size){
pair_r_symbolnum = j + 1;
break;
}
}
if(pair_r_symbolnum == 0){
error_with_cur_obj("r_value (0x%x) field of relocation "
"entry %lu in section (%.16s,%.16s) out of range",
(unsigned int)r_value, i + 1, section_map->s->segname,
section_map->s->sectname);
return;
}
}
input_pc = section_map->s->addr + r_address;
if(r_extern){
if(r_symbolnum >= cur_obj->symtab->nsyms){
error_with_cur_obj("r_symbolnum (%lu) field of external "
"relocation entry %lu in section (%.16s,%.16s) out of "
"range", r_symbolnum, i, section_map->s->segname,
section_map->s->sectname);
return;
}
symbolnum = r_symbolnum;
undefined_map = bsearch(&symbolnum, cur_obj->undefined_maps,
cur_obj->nundefineds, sizeof(struct undefined_map),
(int (*)(const void *, const void *))undef_bsearch);
if(undefined_map != NULL){
merged_symbol = undefined_map->merged_symbol;
}
else{
nlists = (struct nlist *)(cur_obj->obj_addr +
cur_obj->symtab->symoff);
strings = (char *)(cur_obj->obj_addr +
cur_obj->symtab->stroff);
if((nlists[symbolnum].n_type & N_EXT) != N_EXT){
error_with_cur_obj("r_symbolnum (%lu) field of external"
" relocation entry %lu in section (%.16s,%.16s) "
"refers to a non-external symbol", symbolnum, i,
section_map->s->segname, section_map->s->sectname);
return;
}
if((nlists[symbolnum].n_type & N_TYPE) == N_SECT &&
(cur_obj->section_maps[nlists[symbolnum].n_sect-1].
s->flags & SECTION_TYPE) == S_COALESCED){
merged_symbol = lookup_symbol(strings +
nlists[symbolnum].n_un.n_strx);
if(merged_symbol->name_len == 0){
fatal("internal error, in hppa_reloc() failed to "
"lookup coalesced symbol %s", strings +
nlists[symbolnum].n_un.n_strx);
}
}
else{
if((nlists[symbolnum].n_type & N_EXT) != N_EXT ||
(nlists[symbolnum].n_type & N_TYPE) != N_UNDF){
error_with_cur_obj("r_symbolnum (%lu) field of "
"external relocation entry %lu in section "
"(%.16s,%.16s) refers to a non-undefined "
"symbol", symbolnum, i, section_map->s->segname,
section_map->s->sectname);
return;
}
print_obj_name(cur_obj);
fatal("internal error, in hppa_reloc() symbol index %lu"
" in above file not in undefined map", symbolnum);
}
}
if((merged_symbol->nlist.n_type & N_TYPE) == N_SECT &&
(get_output_section(merged_symbol->nlist.n_sect)->
flags & SECTION_TYPE) == S_COALESCED){
if(((merged_symbol->nlist.n_type & N_PEXT) == N_PEXT &&
keep_private_externs == FALSE) ||
dynamic == FALSE ||
(output_for_dyld && has_dynamic_linker_command))
force_extern_reloc = FALSE;
else
force_extern_reloc = TRUE;
}
if((merged_symbol->nlist.n_type & N_TYPE) == N_INDR)
merged_symbol = (struct merged_symbol *)
merged_symbol->nlist.n_value;
if(((merged_symbol->nlist.n_type & N_TYPE) == N_UNDF) ||
(force_extern_reloc == TRUE && prebinding == FALSE) ||
((filetype == MH_DYLIB && multi_module_dylib == TRUE) &&
(((merged_symbol->nlist.n_type & N_PEXT) != N_PEXT) &&
prebinding == FALSE) ) )
value = 0;
else{
value = merged_symbol->nlist.n_value;
if(r_type == HPPA_RELOC_VANILLA){
switch(r_length){
case 0:
offset = get_byte((char *)(contents + r_address));
break;
case 1:
offset = get_short((short *)(contents + r_address));
break;
case 2:
offset = get_long((long *)(contents + r_address));
break;
default:
break;
}
if(r_pcrel)
offset += input_pc;
}
else{
instruction = get_long((long *)(contents + r_address));
switch(r_type){
case HPPA_RELOC_HI21:
offset = (assemble_21(instruction & 0x1fffff) << 11)
+ sign_ext(other_half, 14);
break;
case HPPA_RELOC_LO14:
offset = instruction & 0x3fff;
offset = low_sign_ext(offset, 14) +
(other_half << 11);
break;
case HPPA_RELOC_BR17:
case HPPA_RELOC_BL17:
offset = assemble_17(
(instruction & 0x1f0000) >> 16,
(instruction & 0x1ffc) >> 2,
instruction & 1);
offset = sign_ext(offset, 17);
offset <<= 2;
if(r_type == HPPA_RELOC_BR17)
offset += other_half << 11;
else
offset += 8;
break;
case HPPA_RELOC_JBSR:
offset = sign_ext(other_half, 24);
if((merged_symbol->nlist.n_type & N_TYPE) ==
N_SECT){
other_half = value - output_sections[
merged_symbol->nlist.n_sect]->s.addr +
offset;
other_half = sign_unext(other_half, 24);
}
break;
default:
break;
}
}
}
if((merged_symbol->nlist.n_type & N_TYPE) == N_SECT)
output_sections[merged_symbol->nlist.n_sect]->referenced =
TRUE;
}
else{
value = 0;
if(r_symbolnum != R_ABS){
if(r_symbolnum > cur_obj->nsection_maps){
error_with_cur_obj("r_symbolnum (%lu) field of local "
"relocation entry %lu in section (%.16s,%.16s) "
"out of range", r_symbolnum, i,
section_map->s->segname, section_map->s->sectname);
return;
}
local_map = &(cur_obj->section_maps[r_symbolnum - 1]);
local_map->output_section->referenced = TRUE;
if(local_map->s->flags & S_ATTR_DEBUG){
error_with_cur_obj("illegal reference to debug section,"
" from non-debug section (%.16s,%.16s) via "
"relocation entry (%lu) to section (%.16s,%.16s)",
section_map->s->segname, section_map->s->sectname,
i, local_map->s->segname, local_map->s->sectname);
return;
}
pair_local_map = NULL;
if(r_type == HPPA_RELOC_SECTDIFF ||
r_type == HPPA_RELOC_HI21_SECTDIFF ||
r_type == HPPA_RELOC_LO14_SECTDIFF){
pair_local_map =
&(cur_obj->section_maps[pair_r_symbolnum - 1]);
pair_local_map->output_section->referenced = TRUE;
if(pair_local_map->s->flags & S_ATTR_DEBUG){
error_with_cur_obj("illegal reference to debug "
"section, from non-debug section (%.16s,%.16s) "
"via relocation entry (%lu) to section (%.16s,"
"%.16s)", section_map->s->segname,
section_map->s->sectname, i,
pair_local_map->s->segname,
pair_local_map->s->sectname);
return;
}
}
if(local_map->nfine_relocs == 0 &&
(pair_local_map == NULL ||
pair_local_map->nfine_relocs == 0) ){
if(r_type == HPPA_RELOC_SECTDIFF ||
r_type == HPPA_RELOC_HI21_SECTDIFF ||
r_type == HPPA_RELOC_LO14_SECTDIFF){
value = - local_map->s->addr
+ (local_map->output_section->s.addr +
local_map->offset)
+ pair_local_map->s->addr
- (pair_local_map->output_section->s.addr +
pair_local_map->offset);
}
else{
value = - local_map->s->addr
+ (local_map->output_section->s.addr +
local_map->offset);
}
}
else{
if(r_pcrel) {
if(section_map->nfine_relocs == 0)
output_pc = section_map->output_section->s.addr
+ section_map->offset +
r_address;
else
output_pc = section_map->output_section->s.addr
+
fine_reloc_output_offset(section_map,
r_address);
}
else{
input_pc = 0;
output_pc = 0;
}
if(r_type == HPPA_RELOC_VANILLA ||
r_type == HPPA_RELOC_SECTDIFF){
switch(r_length){
case 0:
value = get_byte((char *)(contents +
r_address));
break;
case 1:
value = get_short((short *)(contents +
r_address));
break;
case 2:
value = get_long((long *)(contents +
r_address));
break;
default:
break;
}
}
else{
instruction = get_long((long *)(contents +
r_address));
switch(r_type){
case HPPA_RELOC_HI21:
case HPPA_RELOC_HI21_SECTDIFF:
value = (assemble_21(instruction & 0x1fffff)
<< 11) + sign_ext(other_half, 14);
break;
case HPPA_RELOC_LO14:
case HPPA_RELOC_LO14_SECTDIFF:
value = instruction & 0x3fff;
value = low_sign_ext(value, 14) +
(other_half << 11);
break;
case HPPA_RELOC_BR17:
case HPPA_RELOC_BL17:
value = assemble_17(
(instruction & 0x1f0000) >> 16,
(instruction & 0x1ffc) >> 2,
instruction & 1);
value = sign_ext(value, 17) << 2;
if(r_type == HPPA_RELOC_BR17)
value += (other_half << 11);
else
value += 8;
break;
case HPPA_RELOC_JBSR:
value = local_map->s->addr +
sign_ext(other_half, 24);
if(r_scattered == 0)
other_half = fine_reloc_output_offset(
local_map, other_half);
else{
other_half = fine_reloc_output_offset(
local_map,
r_value - local_map->s->addr) +
sign_ext(other_half, 24) -
(r_value - local_map->s->addr);
other_half = sign_unext(other_half, 24);
}
break;
default:
break;
}
}
if(r_type == HPPA_RELOC_SECTDIFF ||
r_type == HPPA_RELOC_HI21_SECTDIFF ||
r_type == HPPA_RELOC_LO14_SECTDIFF){
value += input_pc;
offset = value - r_value + pair_r_value;
if(local_map->nfine_relocs != 0){
legal_reference(section_map, r_address,
local_map, r_value - local_map->s->addr +
offset, i, TRUE);
value = fine_reloc_output_address(local_map,
r_value - local_map->s->addr,
local_map->output_section->s.addr);
}
else{
value = local_map->output_section->s.addr +
local_map->offset +
r_value - local_map->s->addr;
}
if(pair_local_map->nfine_relocs != 0){
legal_reference(section_map, r_address,
pair_local_map, pair_r_value -
pair_local_map->s->addr, i, TRUE);
value -=
fine_reloc_output_address(pair_local_map,
pair_r_value - pair_local_map->s->addr,
pair_local_map->output_section->s.addr);
}
else{
value -=
pair_local_map->output_section->s.addr +
pair_local_map->offset +
pair_r_value - pair_local_map->s->addr;
}
value += offset;
value -= output_pc;
}
else{
value += input_pc;
if(r_scattered == 0){
r_value = value;
offset = 0;
}
else{
offset = value - r_value;
}
legal_reference(section_map, r_address, local_map,
r_value - local_map->s->addr + offset, i,
FALSE);
value = fine_reloc_output_address(local_map,
r_value - local_map->s->addr,
local_map->output_section->s.addr);
value -= output_pc;
value += offset;
}
if(r_type == HPPA_RELOC_VANILLA ||
r_type == HPPA_RELOC_SECTDIFF){
switch(r_length){
case 0:
if( (value & 0xffffff00) &&
((value & 0xffffff80) != 0xffffff80))
error_with_cur_obj("relocation for entry "
"%lu in section (%.16s,%.16s) does not "
"fit in 1 byte", i,
section_map->s->segname,
section_map->s->sectname);
set_byte((char *)(contents + r_address), value);
break;
case 1:
if( (value & 0xffff0000) &&
((value & 0xffff8000) != 0xffff8000))
error_with_cur_obj("relocation for entry "
"%lu in section (%.16s,%.16s) does not "
"fit in 2 bytes", i,
section_map->s->segname,
section_map->s->sectname);
set_short((short *)(contents + r_address),
value);
break;
case 2:
set_long((long *)(contents + r_address), value);
break;
default:
error_with_cur_obj("r_length field of "
"relocation entry %lu in section (%.16s,"
"%.16s) invalid", i,
section_map->s->segname,
section_map->s->sectname);
return;
}
}
else{
calc_hppa_HILO(value - offset, offset, &hi21,&lo14);
switch(r_type){
case HPPA_RELOC_HI21:
case HPPA_RELOC_HI21_SECTDIFF:
other_half = lo14 & 0x3fff;
instruction = (instruction & 0xffe00000) |
dis_assemble_21(hi21 >> 11);
break;
case HPPA_RELOC_LO14:
case HPPA_RELOC_LO14_SECTDIFF:
other_half = hi21 >> 11;
lo14 = low_sign_unext(lo14, 14);
instruction = (instruction & 0xffffc000) |
(lo14 & 0x3fff);
break;
case HPPA_RELOC_BR17:
other_half = hi21 >> 11;
if((lo14 & 3) != 0)
error_with_cur_obj("relocation entry %lu in"
" section (%.16s,%.16s) (branch offset "
"not a multiple of 4)", i,
section_map->s->segname,
section_map->s->sectname);
lo14 >>= 2;
dis_assemble_17(lo14, &w1, &w2, &w);
instruction = (instruction & 0xffe0e002) |
(w1 << 16) | (w2 << 2) | w;
break;
case HPPA_RELOC_BL17:
value -= 8;
if((value & 3) != 0)
error_with_cur_obj("relocation entry %lu in"
" section (%.16s,%.16s) (branch offset "
"not a multiple of 4)", i,
section_map->s->segname,
section_map->s->sectname);
if(U_ABS(value) > 0x3ffff)
error_with_cur_obj("relocation overflow "
"for relocation entry %lu in section "
"(%.16s,%.16s) (displacement too large)"
, i, section_map->s->segname,
section_map->s->sectname);
value >>= 2;
dis_assemble_17(value, &w1, &w2, &w);
instruction = (instruction & 0xffe0e002) |
(w1 << 16) | (w2 << 2) | w;
break;
case HPPA_RELOC_JBSR:
if(section_map->nfine_relocs == 0)
value -= section_map->output_section->s.addr
+ section_map->offset + r_address +
8;
else
value -= section_map->output_section->s.addr
+ fine_reloc_output_offset(
section_map, r_address) +
8;
if(save_reloc == 0 &&
((filetype != MH_DYLIB ||
multi_module_dylib == FALSE) ||
(r_extern == 1 &&
(merged_symbol->nlist.n_type & N_PEXT) ==
N_PEXT)) &&
(output_for_dyld == FALSE || r_extern == 0 ||
(merged_symbol->nlist.n_type & N_TYPE) !=
N_UNDF) &&
(U_ABS(value) <= 0x3ffff)){
value = value >> 2;
dis_assemble_17(value, &w1, &w2, &w);
instruction = (instruction & 0xffe0e002) |
(w1 << 16) | (w2 << 2) | w;
}
break;
default:
error_with_cur_obj("r_type field of "
"relocation entry %lu in section (%.16s,"
"%.16s) invalid", i,
section_map->s->segname,
section_map->s->sectname);
return;
}
set_long((long *)(contents + r_address),
instruction);
}
goto update_reloc;
}
}
}
if(r_pcrel){
if(section_map->nfine_relocs == 0)
value += + section_map->s->addr
- (section_map->output_section->s.addr +
section_map->offset );
else
value += + section_map->s->addr + r_address
- (section_map->output_section->s.addr +
fine_reloc_output_offset(section_map,
r_address));
}
if(r_type == HPPA_RELOC_VANILLA ||
r_type == HPPA_RELOC_SECTDIFF){
switch(r_length){
case 0:
value += get_byte((char *)(contents + r_address));
if( (value & 0xffffff00) &&
((value & 0xffffff80) != 0xffffff80))
error_with_cur_obj("relocation for entry %lu in section"
" (%.16s,%.16s) does not fit in 1 byte", i,
section_map->s->segname, section_map->s->sectname);
set_byte((char *)(contents + r_address), value);
break;
case 1:
value += get_short((short *)(contents + r_address));
if( (value & 0xffff0000) &&
((value & 0xffff8000) != 0xffff8000))
error_with_cur_obj("relocation for entry %lu in section"
" (%.16s,%.16s) does not fit in 2 bytes", i,
section_map->s->segname, section_map->s->sectname);
set_short((short *)(contents + r_address), value);
break;
case 2:
value += get_long((long *)(contents + r_address));
set_long((long *)(contents + r_address), value);
break;
default:
error_with_cur_obj("r_length field of relocation entry %lu "
"in section (%.16s,%.16s) invalid", i,
section_map->s->segname, section_map->s->sectname);
return;
}
}
else{
instruction = get_long((long *)(contents + r_address));
switch(r_type){
case HPPA_RELOC_HI21_SECTDIFF:
immediate = sign_ext(other_half, 14) +
(assemble_21(instruction & 0x1fffff) << 11);
calc_hppa_HILO(value + r_value - pair_r_value,
immediate - r_value + pair_r_value,
&hi21, &lo14);
instruction = (instruction & 0xffe00000) |
dis_assemble_21(hi21 >> 11);
other_half = lo14 & 0x3fff;
break;
case HPPA_RELOC_HI21:
immediate = sign_ext(other_half, 14) +
(assemble_21(instruction & 0x1fffff) << 11);
if(r_extern)
calc_hppa_HILO(value, immediate, &hi21, &lo14);
else if(r_scattered)
calc_hppa_HILO(value + r_value, immediate - r_value,
&hi21, &lo14);
else
calc_hppa_HILO(value + immediate, 0, &hi21, &lo14);
instruction = (instruction & 0xffe00000) |
dis_assemble_21(hi21 >> 11);
other_half = lo14 & 0x3fff;
break;
case HPPA_RELOC_LO14:
immediate = low_sign_ext(instruction & 0x3fff, 14);
immediate += (other_half << 11);
if(r_extern)
calc_hppa_HILO(value, immediate, &hi21, &lo14);
else if(r_scattered)
calc_hppa_HILO(value + r_value, immediate - r_value,
&hi21, &lo14);
else
calc_hppa_HILO(value + immediate, 0, &hi21, &lo14);
lo14 = low_sign_unext(lo14, 14);
instruction = (instruction & 0xffffc000) |
(lo14 & 0x3fff);
other_half = hi21 >> 11;
break;
case HPPA_RELOC_LO14_SECTDIFF:
immediate = low_sign_ext(instruction & 0x3fff, 14);
immediate += (other_half << 11);
calc_hppa_HILO(value + r_value - pair_r_value,
immediate - r_value + pair_r_value,
&hi21, &lo14);
lo14 = low_sign_unext(lo14, 14);
instruction = (instruction & 0xffffc000) |
(lo14 & 0x3fff);
other_half = hi21 >> 11;
break;
case HPPA_RELOC_BR17:
immediate = assemble_17((instruction & 0x1f0000) >> 16,
(instruction & 0x1ffc) >> 2,
instruction & 1);
immediate = (sign_ext(immediate, 17) << 2) +
(other_half << 11);
if(r_extern)
calc_hppa_HILO(value, immediate, &hi21, &lo14);
else if(r_scattered)
calc_hppa_HILO(value + r_value, immediate - r_value,
&hi21, &lo14);
else
calc_hppa_HILO(value + immediate, 0, &hi21, &lo14);
lo14 >>= 2;
other_half = hi21 >> 11;
dis_assemble_17(lo14, &w1, &w2, &w);
instruction = (instruction & 0xffe0e002) |
(w1 << 16) | (w2 << 2) | w;
break;
case HPPA_RELOC_BL17:
immediate = assemble_17((instruction & 0x1f0000) >> 16,
(instruction & 0x1ffc) >> 2,
instruction & 1);
if((immediate & 0x10000) != 0)
immediate |= 0xfffe0000;
immediate <<= 2;
immediate += value;
if(U_ABS(immediate) > 0x3ffff)
error_with_cur_obj("relocation overflow "
"for relocation entry %lu in section "
"(%.16s,%.16s) (displacement too large)"
, i, section_map->s->segname,
section_map->s->sectname);
immediate >>= 2;
dis_assemble_17(immediate, &w1, &w2, &w);
instruction = (instruction & 0xffe0e002) |
(w1 << 16) | (w2 << 2) | w;
break;
case HPPA_RELOC_JBSR:
if(r_extern)
value += offset;
else{
value += local_map->s->addr + sign_ext(other_half, 24);
other_half = local_map->offset +
sign_ext(other_half, 24);
}
if(section_map->nfine_relocs == 0)
value += - (section_map->output_section->s.addr +
section_map->offset + r_address +
8);
else
value += - (section_map->output_section->s.addr +
fine_reloc_output_offset(section_map,
r_address) +
8);
if(save_reloc == 0 &&
((filetype != MH_DYLIB || multi_module_dylib == FALSE) ||
(r_extern == 1 &&
(merged_symbol->nlist.n_type & N_PEXT) == N_PEXT)) &&
(output_for_dyld == FALSE || r_extern == 0 ||
(merged_symbol->nlist.n_type & N_TYPE) != N_UNDF) &&
(U_ABS(value) <= 0x3ffff)){
value = value >> 2;
dis_assemble_17(value, &w1, &w2, &w);
instruction = (instruction & 0xffe0e002) |
(w1 << 16) | (w2 << 2) | w;
}
break;
default:
error_with_cur_obj("r_type field of relocation entry %lu "
"in section (%.16s,%.16s) invalid", i,
section_map->s->segname, section_map->s->sectname);
continue;
}
set_long((long *)(contents + r_address), instruction);
}
update_reloc:
;
#ifndef RLD
if(save_reloc || output_for_dyld){
if(r_extern){
if(prebinding == TRUE &&
(section_map->s->flags & SECTION_TYPE) ==
S_LAZY_SYMBOL_POINTERS){
sreloc = (struct scattered_relocation_info *)reloc;
r_scattered = 1;
sreloc->r_scattered = r_scattered;
sreloc->r_address = r_address;
sreloc->r_pcrel = r_pcrel;
sreloc->r_length = r_length;
sreloc->r_type = HPPA_RELOC_PB_LA_PTR;
sreloc->r_value = value;
}
else if((merged_symbol->nlist.n_type & N_TYPE) != N_UNDF &&
(merged_symbol->nlist.n_type & N_TYPE) != N_PBUD &&
force_extern_reloc == FALSE &&
((filetype != MH_DYLIB ||
multi_module_dylib == FALSE) ||
(merged_symbol->nlist.n_type & N_PEXT) == N_PEXT)){
reloc->r_extern = 0;
if(merged_symbol->definition_object == base_obj ||
(merged_symbol->nlist.n_type & N_TYPE) == N_ABS){
reloc->r_symbolnum = R_ABS;
}
else{
if(offset == 0 || output_for_dyld){
reloc->r_symbolnum =merged_symbol->nlist.n_sect;
}
else{
sreloc = (struct scattered_relocation_info *)
reloc;
r_scattered = 1;
sreloc->r_scattered = r_scattered;
sreloc->r_address = r_address;
sreloc->r_pcrel = r_pcrel;
sreloc->r_length = r_length;
sreloc->r_type = r_type;
sreloc->r_value = merged_symbol->nlist.n_value;
}
}
}
else{
reloc->r_symbolnum =
merged_symbol_output_index(merged_symbol);
}
}
else if(r_scattered == 0){
if(prebinding == TRUE &&
(section_map->s->flags & SECTION_TYPE) ==
S_LAZY_SYMBOL_POINTERS){
sreloc = (struct scattered_relocation_info *)reloc;
r_scattered = 1;
sreloc->r_scattered = r_scattered;
sreloc->r_address = r_address;
sreloc->r_pcrel = r_pcrel;
sreloc->r_length = r_length;
sreloc->r_type = HPPA_RELOC_PB_LA_PTR;
sreloc->r_value = value;
}
else if(reloc->r_symbolnum != R_ABS){
if(local_map->nfine_relocs == 0){
reloc->r_symbolnum =
local_map->output_section->output_sectnum;
}
else{
reloc->r_symbolnum =
fine_reloc_output_sectnum(local_map,
r_value - local_map->s->addr);
}
}
}
else{
if(output_for_dyld){
reloc = (struct relocation_info *)sreloc;
r_scattered = 0;
reloc->r_address = r_address;
reloc->r_pcrel = r_pcrel;
reloc->r_extern = 0;
reloc->r_length = r_length;
reloc->r_type = r_type;
if(local_map->nfine_relocs == 0){
reloc->r_symbolnum =
local_map->output_section->output_sectnum;
}
else{
reloc->r_symbolnum =
fine_reloc_output_sectnum(local_map,
r_value - local_map->s->addr);
}
}
else{
if(local_map->nfine_relocs == 0)
sreloc->r_value +=
- local_map->s->addr
+ local_map->output_section->s.addr +
local_map->offset;
else
sreloc->r_value =
fine_reloc_output_address(local_map,
r_value - local_map->s->addr,
local_map->output_section->s.addr);
}
}
if(r_scattered == 0){
if(section_map->nfine_relocs == 0){
reloc->r_address += section_map->offset;
}
else{
reloc->r_address = fine_reloc_output_offset(section_map,
r_address);
}
}
else{
if(section_map->nfine_relocs == 0){
sreloc->r_address += section_map->offset;
}
else{
sreloc->r_address =fine_reloc_output_offset(section_map,
r_address);
}
}
if(pair_r_type == HPPA_RELOC_PAIR){
if(pair_reloc != NULL)
pair_reloc->r_address = other_half;
else if(spair_reloc != NULL){
if(r_type == HPPA_RELOC_SECTDIFF ||
r_type == HPPA_RELOC_HI21_SECTDIFF ||
r_type == HPPA_RELOC_LO14_SECTDIFF){
if(pair_local_map->nfine_relocs == 0)
spair_reloc->r_value +=
- pair_local_map->s->addr
+ (pair_local_map->output_section->s.addr +
pair_local_map->offset);
else
spair_reloc->r_value =
fine_reloc_output_address(pair_local_map,
pair_r_value - pair_local_map->s->addr,
pair_local_map->output_section->s.addr);
if(r_type == HPPA_RELOC_HI21_SECTDIFF ||
r_type == HPPA_RELOC_LO14_SECTDIFF)
spair_reloc->r_address = other_half;
}
else{
spair_reloc->r_address = other_half;
}
}
else{
fatal("internal error, in hppa_reloc() pair_r_type "
"is HPPA_RELOC_PAIR but pair_reloc and spair_reloc "
"are NULL");
}
}
}
#endif
if(pair_r_type == HPPA_RELOC_PAIR)
i++;
}
}