#include <stdlib.h>
#include <string.h>
#include "stuff/rnd.h"
#include "as.h"
#include "sections.h"
#include "frags.h"
#include "symbols.h"
#include "fixes.h"
#include "messages.h"
#include "expr.h"
#include "md.h"
#include "obstack.h"
#include "input-scrub.h"
#include "dwarf2dbg.h"
#if I386
#include "i386.h"
#endif
#ifdef SPARC
#define SPARC_RELOC_13 (127)
#define SPARC_RELOC_22 (126)
#endif
#ifdef ARM
int
arm_force_relocation (struct fix * fixp);
#define TC_FORCE_RELOCATION(FIX) arm_force_relocation (FIX)
#define TC_FORCE_RELOCATION_LOCAL(FIX) \
(!(FIX)->fx_pcrel \
|| TC_FORCE_RELOCATION (FIX))
#ifndef TC_FORCE_RELOCATION
#define TC_FORCE_RELOCATION(FIX) \
(0)
#endif
extern int arm_relax_frag (int nsect, fragS *fragp, int32_t stretch);
#endif
#ifndef MD_PCREL_FROM_SECTION
extern int32_t md_pcrel_from_section(fixS * fixP);
#define MD_PCREL_FROM_SECTION(FIX, SEC) md_pcrel_from_section (FIX)
#endif
static void fixup_section(
fixS *fixP,
int nsect);
#ifndef SPARC
static int is_assembly_time_constant_subtraction_expression(
symbolS *add_symbolP,
int add_symbol_nsect,
symbolS *sub_symbolP,
int sub_symbol_nsect);
#endif
static int relax_section(
struct frag *section_frag_root,
int nsect);
static relax_addressT relax_align(
relax_addressT address,
uint32_t alignment);
#ifndef ARM
static int is_down_range(
struct frag *f1,
struct frag *f2);
#endif
void
add_last_frags_to_sections(
void)
{
struct frchain *frchainP;
if(frchain_root == NULL)
return;
if(frag_now != NULL && frag_now->fr_fix == 0){
frag_now->fr_fix = obstack_next_free(&frags) -
frag_now->fr_literal;
frag_wane(frag_now);
}
for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
(void)obstack_finish(&frags);
frag_now = (fragS *)obstack_alloc(&frags, SIZEOF_STRUCT_FRAG);
memset(frag_now, '\0', SIZEOF_STRUCT_FRAG);
frag_now->fr_next = NULL;
(void)obstack_finish(&frags);
frchainP->frch_last->fr_next = frag_now;
frchainP->frch_last = frag_now;
frag_wane(frag_now);
}
}
void
layout_addresses(
void)
{
struct frchain *frchainP;
fragS *fragP;
relax_addressT slide, tmp;
symbolS *symbolP;
uint32_t nbytes, fill_size, repeat_expression, partial_bytes, layout_pass;
uint32_t section_type;
relax_stateT old_fr_type;
int changed;
if(frchain_root == NULL)
return;
if(frag_now != NULL && frag_now->fr_fix == 0){
frag_now->fr_fix = obstack_next_free(&frags) -
frag_now->fr_literal;
frag_wane(frag_now);
}
for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
(void)obstack_finish(&frags);
frag_now = (fragS *)obstack_alloc(&frags, SIZEOF_STRUCT_FRAG);
memset(frag_now, '\0', SIZEOF_STRUCT_FRAG);
frag_now->fr_next = NULL;
(void)obstack_finish(&frags);
frchainP->frch_last->fr_next = frag_now;
frchainP->frch_last = frag_now;
frag_wane(frag_now);
}
for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
if((frchainP->frch_section.flags & S_ATTR_DEBUG) == S_ATTR_DEBUG)
frchainP->layout_pass = 2;
else if(frchainP->has_rs_leb128s == TRUE)
frchainP->layout_pass = 1;
else
frchainP->layout_pass = 0;
}
for(layout_pass = 0; layout_pass < 3; layout_pass++){
do{
changed = 0;
for(frchainP = frchain_root;
frchainP;
frchainP = frchainP->frch_next){
if(frchainP->layout_pass != layout_pass)
continue;
section_type = frchainP->frch_section.flags & SECTION_TYPE;
if(section_type == S_ZEROFILL ||
section_type == S_THREAD_LOCAL_ZEROFILL)
continue;
frchain_now = frchainP;
changed += relax_section(frchainP->frch_root,
frchainP->frch_nsect);
}
}
while(changed != 0);
}
slide = 0;
for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
section_type = frchainP->frch_section.flags & SECTION_TYPE;
if(section_type == S_ZEROFILL ||
section_type == S_THREAD_LOCAL_ZEROFILL)
continue;
slide = rnd(slide, 1 << frchainP->frch_section.align);
tmp = frchainP->frch_last->fr_address;
if(slide != 0){
for(fragP = frchainP->frch_root; fragP; fragP = fragP->fr_next){
fragP->fr_address += slide;
}
}
slide += tmp;
}
for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
section_type = frchainP->frch_section.flags & SECTION_TYPE;
if(section_type != S_ZEROFILL &&
section_type != S_THREAD_LOCAL_ZEROFILL)
continue;
slide = rnd(slide, 1 << frchainP->frch_section.align);
tmp = frchainP->frch_root->fr_address;
frchainP->frch_root->fr_address = slide;
frchainP->frch_last->fr_address = tmp + slide;
slide += tmp;
}
for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next){
if(symbolP->sy_forward != NULL){
if(symbolP->sy_nlist.n_type & N_STAB)
symbolP->sy_other = symbolP->sy_forward->sy_other;
symbolP->sy_value += symbolP->sy_forward->sy_value +
symbolP->sy_forward->sy_frag->fr_address;
symbolP->sy_forward = 0;
}
}
for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next){
symbolP->sy_value += symbolP->sy_frag->fr_address;
}
for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
frchain_now = frchainP;
for(fragP = frchainP->frch_root; fragP; fragP = fragP->fr_next){
switch(fragP->fr_type){
case rs_align:
case rs_org:
old_fr_type = fragP->fr_type;
fragP->fr_type = rs_fill;
know(fragP->fr_next != NULL);
nbytes = fragP->fr_next->fr_address -
fragP->fr_address -
fragP->fr_fix;
if((int)nbytes < 0){
as_warn("rs_org invalid, dot past value by %d bytes",
nbytes);
nbytes = 0;
}
fill_size = fragP->fr_var;
repeat_expression = nbytes / fill_size;
#ifdef I386
if(old_fr_type == rs_align &&
(frchain_now->frch_section.flags &
S_ATTR_PURE_INSTRUCTIONS) != 0 &&
fill_size == 1 &&
fragP->fr_literal[fragP->fr_fix] == (char)0x90 &&
nbytes > 0 && nbytes < 16 &&
flagseen['k'] == TRUE){
i386_align_code(fragP, nbytes);
fragP->fr_offset = 1;
break;
}
#endif
partial_bytes = nbytes - (repeat_expression * fill_size);
fragP->fr_offset = repeat_expression;
if(partial_bytes != 0){
memmove(fragP->fr_literal +fragP->fr_fix +partial_bytes,
fragP->fr_literal +fragP->fr_fix,
fragP->fr_var);
memset(fragP->fr_literal + fragP->fr_fix,
'\0',
partial_bytes);
fragP->fr_fix += partial_bytes;
}
break;
case rs_fill:
break;
case rs_machine_dependent:
md_convert_frag(fragP);
frag_wane(fragP);
break;
case rs_dwarf2dbg:
dwarf2dbg_convert_frag(fragP);
break;
case rs_leb128:
{
int size;
#ifdef OLD
valueT value = S_GET_VALUE (fragP->fr_symbol);
#else
valueT value;
expressionS *expression;
if(fragP->fr_symbol->expression != NULL){
expression =
(expressionS *)fragP->fr_symbol->expression;
value = 0;
if(expression->X_add_symbol != NULL)
value += expression->X_add_symbol->sy_nlist.n_value;
if(expression->X_subtract_symbol != NULL)
value -=
expression->X_subtract_symbol->sy_nlist.n_value;
value += expression->X_add_number;
}
else{
value = fragP->fr_symbol->sy_nlist.n_value +
fragP->fr_address;
}
#endif
size = output_leb128 (fragP->fr_literal + fragP->fr_fix,
value,
fragP->fr_subtype);
fragP->fr_fix += size;
fragP->fr_type = rs_fill;
fragP->fr_var = 0;
fragP->fr_offset = 0;
fragP->fr_symbol = NULL;
}
break;
default:
BAD_CASE(fragP->fr_type);
break;
}
}
}
for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
now_seg = frchainP->frch_nsect;
fixup_section(frchainP->frch_fix_root, frchainP->frch_nsect);
}
}
static
void
fixup_section(
fixS *fixP,
int nsect)
{
symbolS *add_symbolP;
symbolS *sub_symbolP;
signed_expr_t value;
int size;
char *place;
int32_t where;
char pcrel;
fragS *fragP;
int add_symbol_N_TYPE;
int add_symbol_nsect;
#ifndef SPARC
int sub_symbol_nsect;
#endif
for( ; fixP != NULL; fixP = fixP->fx_next){
fragP = fixP->fx_frag;
know(fragP);
where = fixP->fx_where;
place = fragP->fr_literal + where;
size = fixP->fx_size;
#ifdef TC_FIXUP_SYMBOL
fixP->fx_offset += TC_FIXUP_SYMBOL(fixP, nsect, &fixP->fx_addsy);
fixP->fx_offset -= TC_FIXUP_SYMBOL(fixP, nsect, &fixP->fx_subsy);
#endif
#if defined(I386) && defined(ARCH64)
if(fixP->fx_addsy == fixP->fx_subsy){
fixP->fx_addsy = NULL;
fixP->fx_subsy = NULL;
}
#endif
add_symbolP = fixP->fx_addsy;
sub_symbolP = fixP->fx_subsy;
value = fixP->fx_offset;
pcrel = fixP->fx_pcrel;
#if ARM
if(add_symbolP != NULL && add_symbolP->sy_desc & N_ARM_THUMB_DEF &&
!(sub_symbolP != NULL && sub_symbolP->sy_desc & N_ARM_THUMB_DEF) &&
!pcrel){
value |= 1;
}
#endif
add_symbol_N_TYPE = 0;
add_symbol_nsect = 0;
if(add_symbolP != NULL){
add_symbol_N_TYPE = add_symbolP->sy_type & N_TYPE;
if(add_symbol_N_TYPE == N_SECT)
add_symbol_nsect = add_symbolP->sy_other;
}
if(sub_symbolP){
if(add_symbolP == NULL){
if(sub_symbolP->sy_type != N_ABS)
as_warn("Negative of non-absolute symbol %s",
sub_symbolP->sy_name);
#if !(defined(I386) && defined(ARCH64))
value -= sub_symbolP->sy_value;
#endif
fixP->fx_subsy = NULL;
}
else if((sub_symbolP->sy_type & N_TYPE) == N_ABS &&
(add_symbolP->sy_type & N_TYPE) == N_ABS){
value += add_symbolP->sy_value - sub_symbolP->sy_value;
add_symbolP = NULL;
fixP->fx_addsy = NULL;
fixP->fx_subsy = NULL;
}
else if((sub_symbolP->sy_type & N_TYPE) == N_SECT &&
(add_symbolP->sy_type & N_TYPE) == N_SECT){
#if defined(I386) && !defined(ARCH64)
if(fixP->fx_r_type == GENERIC_RELOC_TLV){
value += fixP->fx_frag->fr_address + where +
fixP->fx_size - sub_symbolP->sy_value;
fixP->fx_subsy = NULL;
fixP->fx_pcrel = TRUE;
goto down;
}
#endif
#ifdef SPARC
if((fixP->fx_r_type == SPARC_RELOC_13) ||
(fixP->fx_r_type == SPARC_RELOC_22)){
if(sub_symbolP->sy_other == add_symbolP->sy_other){
value += add_symbolP->sy_value -
sub_symbolP->sy_value;
add_symbolP = NULL;
fixP->fx_addsy = NULL;
fixP->fx_subsy = NULL;
}
else{
as_warn("Can't emit reloc type %u {-symbol \"%s\"} "
"@ file address %llu (mode?).",
fixP->fx_r_type, sub_symbolP->sy_name,
fragP->fr_address + where);
}
}
else
value += add_symbolP->sy_value - sub_symbolP->sy_value;
#else
#if !(defined(I386) && defined(ARCH64))
value += add_symbolP->sy_value;
value -= sub_symbolP->sy_value;
#else
if(is_section_debug(nsect)){
value += add_symbolP->sy_value;
value -= sub_symbolP->sy_value;
}
#endif
sub_symbol_nsect = sub_symbolP->sy_other;
if(fixP->fx_sectdiff_divide_by_two == 1){
value = value / 2;
if(is_assembly_time_constant_subtraction_expression(
add_symbolP, add_symbol_nsect,
sub_symbolP, sub_symbol_nsect) == TRUE){
fixP->fx_addsy = NULL;
goto down;
}
else{
layout_line = fixP->line;
layout_file = fixP->file;
as_warn("section difference divide by two "
"expression, \"%s\" minus \"%s\" divide by "
"2 will not produce an assembly time "
"constant", add_symbolP->sy_name,
sub_symbolP->sy_name);
}
}
if(is_end_section_address(add_symbol_nsect,
add_symbolP->sy_value) ||
is_end_section_address(sub_symbol_nsect,
sub_symbolP->sy_value)){
if(is_assembly_time_constant_subtraction_expression(
add_symbolP, add_symbol_nsect,
sub_symbolP, sub_symbol_nsect) == TRUE){
fixP->fx_addsy = NULL;
goto down;
}
if(is_section_debug(nsect) &&
strcmp(add_symbolP->sy_name, FAKE_LABEL_NAME) == 0 &&
strcmp(sub_symbolP->sy_name, FAKE_LABEL_NAME) == 0){
fixP->fx_addsy = NULL;
goto down;
}
layout_line = fixP->line;
layout_file = fixP->file;
as_warn("section difference relocatable subtraction "
"expression, \"%s\" minus \"%s\" using a "
"symbol at the end of section will not "
"produce an assembly time constant",
add_symbolP->sy_name, sub_symbolP->sy_name);
as_warn("use a symbol with a constant value created "
"with an assignment instead of the expression, "
"L_const_sym = %s - %s", add_symbolP->sy_name,
sub_symbolP->sy_name);
layout_line = 0;
layout_file = NULL;
}
#endif
goto down;
}
else if(sub_symbolP->sy_type == N_ABS){
value -= sub_symbolP->sy_value;
fixP->fx_subsy = NULL;
}
#if defined(I386) && !defined(ARCH64)
else if(fixP->fx_r_type == GENERIC_RELOC_TLV){
value += fixP->fx_frag->fr_address + where + fixP->fx_size -
sub_symbolP->sy_value;
fixP->fx_subsy = NULL;
fixP->fx_pcrel = TRUE;
}
#endif
else{
layout_line = fixP->line;
layout_file = fixP->file;
as_bad("non-relocatable subtraction expression, \"%s\" "
"minus \"%s\"", add_symbolP->sy_name,
sub_symbolP->sy_name);
if((add_symbolP->sy_type & N_TYPE) == N_UNDF)
as_bad("symbol: \"%s\" can't be undefined in a "
"subtraction expression", add_symbolP->sy_name);
if((sub_symbolP->sy_type & N_TYPE) == N_UNDF)
as_bad("symbol: \"%s\" can't be undefined in a "
"subtraction expression", sub_symbolP->sy_name);
layout_line = 0;
layout_file = NULL;
}
}
if(add_symbolP){
if(add_symbol_nsect == nsect
#ifdef ARM
&& !TC_FORCE_RELOCATION_LOCAL (fixP)
#else
&& pcrel
#endif
&& !(fixP->fx_pcrel_reloc)){
value += add_symbolP->sy_value;
#ifdef ARM
value -= MD_PCREL_FROM_SECTION (fixP, nsect);
#else
value -= size + where + fragP->fr_address;
#endif
pcrel = 0;
fixP->fx_addsy = NULL;
}
else{
switch(add_symbol_N_TYPE){
case N_ABS:
if(add_symbolP->expression != NULL){
expressionS *exp;
exp = (expressionS *)add_symbolP->expression;
value +=
exp->X_add_symbol->sy_value +
exp->X_add_number -
exp->X_subtract_symbol->sy_value;
}
else
{
value += add_symbolP->sy_value;
}
fixP->fx_addsy = NULL;
add_symbolP = NULL;
break;
case N_SECT:
#if (defined(I386) && defined(ARCH64))
if((is_section_debug(nsect) &&
add_symbol_N_TYPE != N_UNDF) ||
(add_symbol_N_TYPE == N_SECT &&
is_local_symbol(add_symbolP) &&
!is_section_cstring_literals(add_symbol_nsect)) )
#else
if(((add_symbolP->sy_type & N_EXT) != N_EXT ||
add_symbol_N_TYPE != N_SECT ||
!is_section_coalesced(add_symbol_nsect)) &&
(add_symbolP->sy_desc & N_WEAK_DEF) != N_WEAK_DEF
#if defined(I386) && !defined(ARCH64)
&&
fixP->fx_r_type != GENERIC_RELOC_TLV
#endif
)
#endif
value += add_symbolP->sy_value;
break;
case N_UNDF:
break;
default:
BAD_CASE(add_symbol_N_TYPE);
break;
}
}
}
down:
if(pcrel){
#ifdef ARM
value -= MD_PCREL_FROM_SECTION (fixP, nsect);
#elif !(defined(I386) && defined(ARCH64))
value -= size + where + fragP->fr_address;
#endif
if(add_symbolP == NULL){
fixP->fx_addsy = &abs_symbol;
}
}
if((size == 1 && (value & 0xffffff00) &&
((value & 0xffffff80) != 0xffffff80)) ||
(size == 2 && (value & 0xffff0000) &&
((value & 0xffff8000) != 0xffff8000))){
layout_line = fixP->line;
layout_file = fixP->file;
as_bad("Fixup of %lld too large for field width of %d",
value, size);
layout_line = 0;
layout_file = NULL;
}
md_number_to_imm((unsigned char *)place, value, size, fixP, nsect);
fixP->fx_value = value;
if(is_section_non_lazy_symbol_pointers(nsect) &&
(add_symbolP->sy_type & N_EXT) != N_EXT &&
sub_symbolP == NULL){
fixP->fx_addsy = NULL;
}
}
}
#ifndef SPARC
static
int
is_assembly_time_constant_subtraction_expression(
symbolS *add_symbolP,
int add_symbol_nsect,
symbolS *sub_symbolP,
int sub_symbol_nsect)
{
struct frchain *frchainP;
uint32_t section_type, section_attributes;
symbolS *prev_symbol;
int non_assembly_temporary_symbol;
if(add_symbolP->sy_name == NULL || add_symbolP->sy_name[0] != 'L' ||
sub_symbolP->sy_name == NULL || sub_symbolP->sy_name[0] != 'L')
return(0);
if(flagseen[(int)'L'])
return(0);
if(add_symbol_nsect != sub_symbol_nsect)
return(0);
section_attributes = 0;
for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
if(frchainP->frch_nsect == add_symbol_nsect){
section_type = frchainP->frch_section.flags & SECTION_TYPE;
section_attributes = frchainP->frch_section.flags &
SECTION_ATTRIBUTES;
if(section_type == S_REGULAR || section_type == S_COALESCED)
break;
else
return(0);
}
}
non_assembly_temporary_symbol = 0;
for(prev_symbol = add_symbolP->sy_prev_by_index;
prev_symbol != NULL;
prev_symbol = prev_symbol->sy_prev_by_index){
if((prev_symbol->sy_type & N_SECT) == N_SECT &&
(prev_symbol->sy_type & N_STAB) == 0 &&
prev_symbol->sy_other == add_symbol_nsect){
if(prev_symbol == sub_symbolP){
if(non_assembly_temporary_symbol == 0)
return(1);
else
return(0);
}
if(prev_symbol->sy_name != NULL &&
prev_symbol->sy_name[0] != 'L')
non_assembly_temporary_symbol = 1;
}
}
non_assembly_temporary_symbol = 0;
for(prev_symbol = sub_symbolP->sy_prev_by_index;
prev_symbol != NULL;
prev_symbol = prev_symbol->sy_prev_by_index){
if((prev_symbol->sy_type & N_SECT) == N_SECT &&
(prev_symbol->sy_type & N_STAB) == 0 &&
prev_symbol->sy_other == sub_symbol_nsect){
if(prev_symbol == add_symbolP){
if(non_assembly_temporary_symbol == 0)
return(1);
else
return(0);
}
if(prev_symbol->sy_name != NULL &&
prev_symbol->sy_name[0] != 'L')
non_assembly_temporary_symbol = 1;
}
}
if((section_attributes & S_ATTR_DEBUG) == S_ATTR_DEBUG &&
strcmp(add_symbolP->sy_name, FAKE_LABEL_NAME) == 0 &&
strcmp(sub_symbolP->sy_name, FAKE_LABEL_NAME) == 0)
return(1);
return(0);
}
#endif
static
int
relax_section(
struct frag *frag_root,
int nsect)
{
struct frag *fragP;
relax_addressT address;
int32_t stretch;
int32_t stretched;
#ifndef ARM
const relax_typeS *this_type;
const relax_typeS *start_type;
relax_substateT next_state;
relax_substateT this_state;
int32_t aim;
#endif
int32_t growth;
uint32_t was_address;
int32_t offset;
symbolS *symbolP;
int32_t target;
int32_t after;
uint32_t oldoff, newoff;
int ret;
ret = 0;
growth = 0;
address = 0;
for(fragP = frag_root; fragP != NULL; fragP = fragP->fr_next){
#ifdef ARM
fragP->relax_marker = 0;
#endif
fragP->fr_address = address;
address += fragP->fr_fix;
switch(fragP->fr_type){
case rs_fill:
address += fragP->fr_offset * fragP->fr_var;
break;
case rs_align:
offset = relax_align (address, (int) fragP->fr_offset);
if(fragP->fr_subtype != 0){
if(offset > (int32_t)fragP->fr_subtype){
offset = 0;
}
else{
if(frchain_now->frch_section.align <
(uint32_t)fragP->fr_offset)
frchain_now->frch_section.align = fragP->fr_offset;
}
}
address += offset;
break;
case rs_org:
break;
case rs_machine_dependent:
address += md_estimate_size_before_relax(fragP, nsect);
break;
case rs_dwarf2dbg:
address += dwarf2dbg_estimate_size_before_relax(fragP);
break;
case rs_leb128:
address += fragP->fr_offset = 1;
break;
default:
BAD_CASE(fragP->fr_type);
break;
}
}
do{
stretch = 0;
stretched = 0;
for(fragP = frag_root; fragP != NULL; fragP = fragP->fr_next){
#ifdef ARM
fragP->relax_marker ^= 1;
#endif
was_address = fragP->fr_address;
fragP->fr_address += stretch;
address = fragP->fr_address;
symbolP = fragP->fr_symbol;
offset = fragP->fr_offset;
switch(fragP->fr_type){
case rs_fill:
growth = 0;
break;
case rs_align:
oldoff = relax_align(was_address + fragP->fr_fix, offset);
newoff = relax_align(address + fragP->fr_fix, offset);
if(fragP->fr_subtype != 0){
if(oldoff > fragP->fr_subtype)
oldoff = 0;
if(newoff > fragP->fr_subtype)
newoff = 0;
}
growth = newoff - oldoff;
break;
case rs_org:
target = offset;
if(symbolP != NULL){
know(((symbolP->sy_type & N_TYPE) == N_ABS) ||
((symbolP->sy_type & N_TYPE) == N_SECT));
know(symbolP->sy_frag);
know((symbolP->sy_type & N_TYPE) != N_ABS ||
symbolP->sy_frag == &zero_address_frag );
target += symbolP->sy_value +
symbolP->sy_frag->fr_address;
}
know(fragP->fr_next);
after = fragP->fr_next->fr_address;
growth = ((target - after ) > 0) ? (target - after) : 0;
growth -= stretch;
break;
case rs_machine_dependent:
#ifdef ARM
growth = arm_relax_frag(nsect, fragP, stretch);
#else
this_state = fragP->fr_subtype;
this_type = md_relax_table + this_state;
start_type = this_type;
target = offset;
if(symbolP){
know(((symbolP->sy_type & N_TYPE) == N_ABS) ||
((symbolP->sy_type & N_TYPE) == N_SECT));
know(symbolP->sy_frag);
know((symbolP->sy_type & N_TYPE) != N_ABS ||
symbolP->sy_frag == &zero_address_frag);
target += symbolP->sy_value +
symbolP->sy_frag->fr_address;
if(symbolP->sy_frag->fr_address >= was_address &&
is_down_range(fragP, symbolP->sy_frag))
target += stretch;
}
aim = target - address - fragP->fr_fix;
if(aim < 0){
for(next_state = this_type->rlx_more; next_state; ){
if(aim >= this_type->rlx_backward)
next_state = 0;
else{
this_state = next_state;
this_type = md_relax_table + this_state;
next_state = this_type->rlx_more;
}
}
}
else{
for(next_state = this_type->rlx_more; next_state; ){
if(aim <= this_type->rlx_forward)
next_state = 0;
else{
this_state = next_state;
this_type = md_relax_table + this_state;
next_state = this_type->rlx_more;
}
}
}
if((growth = this_type->rlx_length -start_type->rlx_length))
fragP->fr_subtype = this_state;
#endif
break;
case rs_dwarf2dbg:
growth = dwarf2dbg_relax_frag(fragP);
break;
case rs_leb128:
{
valueT value;
offsetT size;
#ifdef OLD
value = resolve_symbol_value (fragP->fr_symbol);
#else
expressionS *expression;
if(fragP->fr_symbol->expression != NULL){
expression =
(expressionS *)fragP->fr_symbol->expression;
value = 0;
if(expression->X_add_symbol != NULL)
value +=
(expression->X_add_symbol->sy_nlist.n_value +
expression->X_add_symbol->sy_frag->fr_address);
if(expression->X_subtract_symbol != NULL)
value -=
(expression->X_subtract_symbol->sy_nlist.n_value +
expression->X_subtract_symbol->
sy_frag->fr_address);
value += expression->X_add_number;
}
else{
value = fragP->fr_symbol->sy_nlist.n_value +
fragP->fr_address;
}
#endif
size = sizeof_leb128 (value, fragP->fr_subtype);
growth = size - fragP->fr_offset;
fragP->fr_offset = size;
}
break;
default:
BAD_CASE(fragP->fr_type);
break;
}
if(growth) {
stretch += growth;
stretched++;
}
}
}while(stretched);
for(fragP = frag_root; fragP != NULL; fragP = fragP->fr_next){
if(fragP->last_fr_address != fragP->fr_address){
fragP->last_fr_address = fragP->fr_address;
ret = 1;
}
}
return(ret);
}
static
relax_addressT
relax_align(
relax_addressT address,
uint32_t alignment)
{
relax_addressT mask;
relax_addressT new_address;
mask = ~ ( (~0) << alignment );
new_address = (address + mask) & (~ mask);
return(new_address - address);
}
#ifndef ARM
static
int
is_down_range(
struct frag *f1,
struct frag *f2)
{
while(f1){
if(f1->fr_next == f2)
return(1);
f1 = f1->fr_next;
}
return(0);
}
#endif