Polishing m68k support.
This commit is contained in:
parent
0285f1792f
commit
f6e504fe91
@ -2,6 +2,4 @@
|
||||
|
||||
#include <ho-sunos.h>
|
||||
|
||||
extern int sprintf();
|
||||
|
||||
/* end of ho-sun3.h */
|
||||
|
@ -5,7 +5,7 @@ This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 1,
|
||||
published by the Free Software Foundation; either version 2,
|
||||
or (at your option) any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful, but
|
||||
@ -133,13 +133,15 @@ typedef struct nlist obj_symbol_type; /* Symbol table entry */
|
||||
|
||||
/* File header macro and type definition */
|
||||
|
||||
#define H_GET_FILE_SIZE(h) (sizeof(struct exec) + \
|
||||
H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h) + \
|
||||
H_GET_SYMBOL_TABLE_SIZE(h) + \
|
||||
H_GET_TEXT_RELOCATION_SIZE(h) + \
|
||||
H_GET_DATA_RELOCATION_SIZE(h) + \
|
||||
(h)->string_table_size)
|
||||
#define H_GET_FILE_SIZE(h) (H_GET_HEADER_SIZE(h) \
|
||||
+ H_GET_TEXT_SIZE(h) \
|
||||
+ H_GET_DATA_SIZE(h) \
|
||||
+ H_GET_SYMBOL_TABLE_SIZE(h) \
|
||||
+ H_GET_TEXT_RELOCATION_SIZE(h) \
|
||||
+ H_GET_DATA_RELOCATION_SIZE(h) \
|
||||
+ H_GET_STRING_SIZE(h))
|
||||
|
||||
#define H_GET_HEADER_SIZE(h) (sizeof(struct exec))
|
||||
#define H_GET_TEXT_SIZE(h) ((h)->header.a_text)
|
||||
#define H_GET_DATA_SIZE(h) ((h)->header.a_data)
|
||||
#define H_GET_BSS_SIZE(h) ((h)->header.a_bss)
|
||||
@ -149,9 +151,12 @@ typedef struct nlist obj_symbol_type; /* Symbol table entry */
|
||||
#define H_GET_MAGIC_NUMBER(h) ((h)->header.a_info)
|
||||
#define H_GET_ENTRY_POINT(h) ((h)->header.a_entry)
|
||||
#define H_GET_STRING_SIZE(h) ((h)->string_table_size)
|
||||
#define H_GET_LINENO_SIZE(h) (0)
|
||||
|
||||
#ifdef EXEC_MACHINE_TYPE
|
||||
#define H_GET_MACHINE_TYPE(h) ((h)->header.a_machtype)
|
||||
#endif /* EXEC_MACHINE_TYPE */
|
||||
|
||||
#ifdef EXEC_VERSION
|
||||
#define H_GET_VERSION(h) ((h)->header.a_version)
|
||||
#endif /* EXEC_VERSION */
|
||||
|
@ -927,7 +927,8 @@ md_ri_to_chars(the_bytes, ri)
|
||||
}
|
||||
|
||||
/* should never be called for 29k */
|
||||
void md_convert_frag(fragP)
|
||||
void md_convert_frag(headers, fragP)
|
||||
object_headers *headers;
|
||||
register fragS *fragP;
|
||||
{
|
||||
fprintf(stderr, "sparc_convert_frag\n");
|
||||
|
@ -6,7 +6,7 @@ This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful,
|
||||
@ -26,6 +26,15 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* note that this file includes real declarations and thus can only be included by one source file per executable. */
|
||||
#include "m68k-opcode.h"
|
||||
#ifdef TE_SUN
|
||||
/* This variable contains the value to write out at the beginning of
|
||||
the a.out file. The 2<<16 means that this is a 68020 file instead
|
||||
of an old-style 68000 file */
|
||||
|
||||
long omagic = 2<<16|OMAGIC; /* Magic byte for header file */
|
||||
#else
|
||||
long omagic = OMAGIC;
|
||||
#endif
|
||||
|
||||
/* This array holds the chars that always start a comment. If the
|
||||
pre-processor is disabled, these aren't very useful */
|
||||
@ -74,6 +83,76 @@ static struct obstack robyn;
|
||||
#define DBCC 5
|
||||
#define PCLEA 6
|
||||
|
||||
/* Operands we can parse: (And associated modes)
|
||||
|
||||
numb: 8 bit num
|
||||
numw: 16 bit num
|
||||
numl: 32 bit num
|
||||
dreg: data reg 0-7
|
||||
reg: address or data register
|
||||
areg: address register
|
||||
apc: address register, PC, ZPC or empty string
|
||||
num: 16 or 32 bit num
|
||||
num2: like num
|
||||
sz: w or l if omitted, l assumed
|
||||
scale: 1 2 4 or 8 if omitted, 1 assumed
|
||||
|
||||
7.4 IMMED #num --> NUM
|
||||
0.? DREG dreg --> dreg
|
||||
1.? AREG areg --> areg
|
||||
2.? AINDR areg@ --> *(areg)
|
||||
3.? AINC areg@+ --> *(areg++)
|
||||
4.? ADEC areg@- --> *(--areg)
|
||||
5.? AOFF apc@(numw) --> *(apc+numw) -- empty string and ZPC not allowed here
|
||||
6.? AINDX apc@(num,reg:sz:scale) --> *(apc+num+reg*scale)
|
||||
6.? AINDX apc@(reg:sz:scale) --> same, with num=0
|
||||
6.? APODX apc@(num)@(num2,reg:sz:scale) --> *(*(apc+num)+num2+reg*scale)
|
||||
6.? APODX apc@(num)@(reg:sz:scale) --> same, with num2=0
|
||||
6.? AMIND apc@(num)@(num2) --> *(*(apc+num)+num2) (previous mode without an index reg)
|
||||
6.? APRDX apc@(num,reg:sz:scale)@(num2) --> *(*(apc+num+reg*scale)+num2)
|
||||
6.? APRDX apc@(reg:sz:scale)@(num2) --> same, with num=0
|
||||
7.0 ABSL num:sz --> *(num)
|
||||
num --> *(num) (sz L assumed)
|
||||
*** MSCR otherreg --> Magic
|
||||
With -l option
|
||||
5.? AOFF apc@(num) --> *(apc+num) -- empty string and ZPC not allowed here still
|
||||
|
||||
examples:
|
||||
#foo #0x35 #12
|
||||
d2
|
||||
a4
|
||||
a3@
|
||||
a5@+
|
||||
a6@-
|
||||
a2@(12) pc@(14)
|
||||
a1@(5,d2:w:1) @(45,d6:l:4)
|
||||
pc@(a2) @(d4)
|
||||
etc . . .
|
||||
|
||||
|
||||
#name@(numw) -->turn into PC rel mode
|
||||
apc@(num8,reg:sz:scale) --> *(apc+num8+reg*scale)
|
||||
|
||||
*/
|
||||
|
||||
enum operand_type {
|
||||
IMMED = 1,
|
||||
DREG,
|
||||
AREG,
|
||||
AINDR,
|
||||
ADEC,
|
||||
AINC,
|
||||
AOFF,
|
||||
AINDX,
|
||||
APODX,
|
||||
AMIND,
|
||||
APRDX,
|
||||
ABSL,
|
||||
MSCR,
|
||||
REGLST,
|
||||
};
|
||||
|
||||
|
||||
struct m68k_exp {
|
||||
char *e_beg;
|
||||
char *e_end;
|
||||
@ -84,7 +163,7 @@ struct m68k_exp {
|
||||
/* Internal form of an operand. */
|
||||
struct m68k_op {
|
||||
char *error; /* Couldn't parse it */
|
||||
int mode; /* What mode this instruction is in. */
|
||||
enum operand_type mode; /* What mode this instruction is in. */
|
||||
unsigned long reg; /* Base register */
|
||||
struct m68k_exp *con1;
|
||||
int ireg; /* Index register */
|
||||
@ -313,73 +392,6 @@ const pseudo_typeS md_pseudo_table[] = {
|
||||
|
||||
extern char *input_line_pointer;
|
||||
|
||||
/* Operands we can parse: (And associated modes)
|
||||
|
||||
numb: 8 bit num
|
||||
numw: 16 bit num
|
||||
numl: 32 bit num
|
||||
dreg: data reg 0-7
|
||||
reg: address or data register
|
||||
areg: address register
|
||||
apc: address register, PC, ZPC or empty string
|
||||
num: 16 or 32 bit num
|
||||
num2: like num
|
||||
sz: w or l if omitted, l assumed
|
||||
scale: 1 2 4 or 8 if omitted, 1 assumed
|
||||
|
||||
7.4 IMMED #num --> NUM
|
||||
0.? DREG dreg --> dreg
|
||||
1.? AREG areg --> areg
|
||||
2.? AINDR areg@ --> *(areg)
|
||||
3.? AINC areg@+ --> *(areg++)
|
||||
4.? ADEC areg@- --> *(--areg)
|
||||
5.? AOFF apc@(numw) --> *(apc+numw) -- empty string and ZPC not allowed here
|
||||
6.? AINDX apc@(num,reg:sz:scale) --> *(apc+num+reg*scale)
|
||||
6.? AINDX apc@(reg:sz:scale) --> same, with num=0
|
||||
6.? APODX apc@(num)@(num2,reg:sz:scale) --> *(*(apc+num)+num2+reg*scale)
|
||||
6.? APODX apc@(num)@(reg:sz:scale) --> same, with num2=0
|
||||
6.? AMIND apc@(num)@(num2) --> *(*(apc+num)+num2) (previous mode without an index reg)
|
||||
6.? APRDX apc@(num,reg:sz:scale)@(num2) --> *(*(apc+num+reg*scale)+num2)
|
||||
6.? APRDX apc@(reg:sz:scale)@(num2) --> same, with num=0
|
||||
7.0 ABSL num:sz --> *(num)
|
||||
num --> *(num) (sz L assumed)
|
||||
*** MSCR otherreg --> Magic
|
||||
With -l option
|
||||
5.? AOFF apc@(num) --> *(apc+num) -- empty string and ZPC not allowed here still
|
||||
|
||||
examples:
|
||||
#foo #0x35 #12
|
||||
d2
|
||||
a4
|
||||
a3@
|
||||
a5@+
|
||||
a6@-
|
||||
a2@(12) pc@(14)
|
||||
a1@(5,d2:w:1) @(45,d6:l:4)
|
||||
pc@(a2) @(d4)
|
||||
etc . . .
|
||||
|
||||
|
||||
#name@(numw) -->turn into PC rel mode
|
||||
apc@(num8,reg:sz:scale) --> *(apc+num8+reg*scale)
|
||||
|
||||
*/
|
||||
|
||||
#define IMMED 1
|
||||
#define DREG 2
|
||||
#define AREG 3
|
||||
#define AINDR 4
|
||||
#define ADEC 5
|
||||
#define AINC 6
|
||||
#define AOFF 7
|
||||
#define AINDX 8
|
||||
#define APODX 9
|
||||
#define AMIND 10
|
||||
#define APRDX 11
|
||||
#define ABSL 12
|
||||
#define MSCR 13
|
||||
#define REGLST 14
|
||||
|
||||
#define FAIL 0
|
||||
#define OK 1
|
||||
|
||||
@ -677,6 +689,7 @@ register struct m68k_op *opP;
|
||||
{
|
||||
char *strend;
|
||||
long i;
|
||||
char *parse_index();
|
||||
|
||||
if(*str==' ')
|
||||
str++;
|
||||
@ -705,7 +718,7 @@ register struct m68k_op *opP;
|
||||
opP->mode=REGLST;
|
||||
return get_regs(i,str,opP);
|
||||
}
|
||||
if((stmp=strchr(str,'@')) != '\0') {
|
||||
if ((stmp=strchr(str,'@')) != '\0') {
|
||||
opP->con1=add_exp(str,stmp-1);
|
||||
if(stmp==strend) {
|
||||
opP->mode=AINDX;
|
||||
@ -1018,6 +1031,7 @@ char *instring;
|
||||
char c;
|
||||
int losing;
|
||||
int opsfound;
|
||||
char *crack_operand();
|
||||
LITTLENUM_TYPE words[6];
|
||||
LITTLENUM_TYPE *wordp;
|
||||
|
||||
@ -1033,7 +1047,7 @@ char *instring;
|
||||
|
||||
if (p == instring) {
|
||||
the_ins.error = "No operator";
|
||||
the_ins.opcode[0] = (short) NULL;
|
||||
the_ins.opcode[0] = NULL;
|
||||
/* the_ins.numo=1; */
|
||||
return;
|
||||
}
|
||||
@ -1048,7 +1062,7 @@ char *instring;
|
||||
|
||||
if (opcode == NULL) {
|
||||
the_ins.error = "Unknown operator";
|
||||
the_ins.opcode[0] = (short) NULL;
|
||||
the_ins.opcode[0] = NULL;
|
||||
/* the_ins.numo=1; */
|
||||
return;
|
||||
}
|
||||
@ -1385,7 +1399,7 @@ char *instring;
|
||||
switch(opP->mode) {
|
||||
case IMMED:
|
||||
tmpreg=0x3c; /* 7.4 */
|
||||
if(strchr("bwl",s[1])) nextword=get_num(opP->con1,80);
|
||||
if (strchr("bwl",s[1])) nextword=get_num(opP->con1,80);
|
||||
else nextword=nextword=get_num(opP->con1,0);
|
||||
if(isvar(opP->con1))
|
||||
add_fix(s[1],opP->con1,0);
|
||||
@ -1434,7 +1448,7 @@ char *instring;
|
||||
/* We gotta put out some float */
|
||||
if(seg(opP->con1)!=SEG_BIG) {
|
||||
int_to_gen(nextword);
|
||||
gen_to_words(words,baseo,(long)outro);
|
||||
gen_to_words(words,baseo,(long int)outro);
|
||||
for(wordp=words;baseo--;wordp++)
|
||||
addword(*wordp);
|
||||
break;
|
||||
@ -1442,7 +1456,7 @@ char *instring;
|
||||
if(offs(opP->con1)>0) {
|
||||
as_warn("Bignum assumed to be binary bit-pattern");
|
||||
if(offs(opP->con1)>baseo) {
|
||||
as_bad("Bignum too big for %c format; truncated",s[1]);
|
||||
as_warn("Bignum too big for %c format; truncated",s[1]);
|
||||
offs(opP->con1)=baseo;
|
||||
}
|
||||
baseo-=offs(opP->con1);
|
||||
@ -1453,7 +1467,7 @@ char *instring;
|
||||
break;
|
||||
}
|
||||
gen_to_words(words,baseo,(long)outro);
|
||||
for(wordp=words;baseo--;wordp++)
|
||||
for (wordp=words;baseo--;wordp++)
|
||||
addword(*wordp);
|
||||
break;
|
||||
case DREG:
|
||||
@ -1664,16 +1678,21 @@ char *instring;
|
||||
nextword=get_num(opP->con1,80);
|
||||
switch(opP->con1->e_siz) {
|
||||
default:
|
||||
as_bad("Unknown size for absolute reference");
|
||||
as_warn("Unknown size for absolute reference");
|
||||
case 0:
|
||||
if(!isvar(opP->con1) && issword(offs(opP->con1))) {
|
||||
tmpreg=0x38; /* 7.0 */
|
||||
addword(nextword);
|
||||
break;
|
||||
}
|
||||
/* Don't generate pc relative code
|
||||
on 68010 and 68000 */
|
||||
if(isvar(opP->con1) &&
|
||||
!subs(opP->con1) &&
|
||||
!strchr("~%&$?", s[0])) {
|
||||
seg(opP->con1)==SEG_TEXT &&
|
||||
now_seg==SEG_TEXT &&
|
||||
flagseen['m']==0 &&
|
||||
!strchr("~%&$?", s[0])) {
|
||||
tmpreg=0x3A; /* 7.2 */
|
||||
add_frag(adds(opP->con1),
|
||||
offs(opP->con1),
|
||||
@ -1769,46 +1788,46 @@ char *instring;
|
||||
case 'B':
|
||||
tmpreg=get_num(opP->con1,80);
|
||||
switch(s[1]) {
|
||||
case 'B':
|
||||
/* Needs no offsetting */
|
||||
add_fix('B',opP->con1,1);
|
||||
break;
|
||||
case 'W':
|
||||
/* Offset the displacement to be relative to byte disp location */
|
||||
opP->con1->e_exp.X_add_number+=2;
|
||||
add_fix('w',opP->con1,1);
|
||||
addword(0);
|
||||
break;
|
||||
case 'L':
|
||||
long_branch:
|
||||
if(flagseen['m']) /* 68000 or 010 */
|
||||
as_warn("Can't use long branches on 68000/68010");
|
||||
the_ins.opcode[the_ins.numo-1]|=0xff;
|
||||
/* Offset the displacement to be relative to byte disp location */
|
||||
opP->con1->e_exp.X_add_number+=4;
|
||||
add_fix('l',opP->con1,1);
|
||||
addword(0);
|
||||
addword(0);
|
||||
break;
|
||||
case 'g':
|
||||
if(opP->con1->e_siz) { /* Deal with fixed size stuff by hand */
|
||||
switch(opP->con1->e_siz) {
|
||||
case 1:
|
||||
add_fix('b',opP->con1,1);
|
||||
break;
|
||||
case 2:
|
||||
add_fix('w',opP->con1,1);
|
||||
addword(0);
|
||||
break;
|
||||
case 3:
|
||||
add_fix('l',opP->con1,1);
|
||||
addword(0);
|
||||
addword(0);
|
||||
break;
|
||||
default:
|
||||
as_bad("Bad size for expression %d", opP->con1->e_siz);
|
||||
}
|
||||
} else if(subs(opP->con1)) {
|
||||
/* We can't relax it */
|
||||
the_ins.opcode[the_ins.numo-1]|=0xff;
|
||||
add_fix('l',opP->con1,1);
|
||||
addword(0);
|
||||
addword(0);
|
||||
} else if(adds(opP->con1)) {
|
||||
if (flagseen['m'] &&
|
||||
(the_ins.opcode[0] >= 0x6200) &&
|
||||
(the_ins.opcode[0] <= 0x6f00)) {
|
||||
add_frag(adds(opP->con1),offs(opP->con1),TAB(BCC68000,SZ_UNDEF));
|
||||
} else {
|
||||
add_frag(adds(opP->con1),offs(opP->con1),TAB(BRANCH,SZ_UNDEF));
|
||||
}
|
||||
if(subs(opP->con1)) /* We can't relax it */
|
||||
goto long_branch;
|
||||
|
||||
/* This could either be a symbol, or an
|
||||
absolute address. No matter, the
|
||||
frag hacking will finger it out.
|
||||
Not quite: it can't switch from
|
||||
BRANCH to BCC68000 for the case
|
||||
where opnd is absolute (it needs
|
||||
to use the 68000 hack since no
|
||||
conditional abs jumps). */
|
||||
if(
|
||||
(flagseen['m'] || (0==adds(opP->con1)))
|
||||
&& (the_ins.opcode[0] >= 0x6200) &&
|
||||
(the_ins.opcode[0] <= 0x6f00)) {
|
||||
add_frag(adds(opP->con1),offs(opP->con1),TAB(BCC68000,SZ_UNDEF));
|
||||
} else {
|
||||
/* JF: This is the WRONG thing to do
|
||||
add_frag((symbolS *)0,offs(opP->con1),TAB(BRANCH,BYTE)); */
|
||||
the_ins.opcode[the_ins.numo-1]|=0xff;
|
||||
offs(opP->con1)+=4;
|
||||
add_fix('l',opP->con1,1);
|
||||
addword(0);
|
||||
addword(0);
|
||||
add_frag(adds(opP->con1),offs(opP->con1),TAB(BRANCH,SZ_UNDEF));
|
||||
}
|
||||
break;
|
||||
case 'w':
|
||||
@ -1827,24 +1846,18 @@ char *instring;
|
||||
}
|
||||
addword(0);
|
||||
break;
|
||||
case 'c':
|
||||
if(opP->con1->e_siz) {
|
||||
switch(opP->con1->e_siz) {
|
||||
case 2:
|
||||
add_fix('w',opP->con1,1)
|
||||
addword(0);
|
||||
break;
|
||||
case 3:
|
||||
the_ins.opcode[the_ins.numo-1]|=0x40;
|
||||
add_fix('l',opP->con1,1);
|
||||
addword(0);
|
||||
addword(0);
|
||||
break;
|
||||
default:
|
||||
as_bad("Bad size for offset, must be word or long");
|
||||
break;
|
||||
}
|
||||
} else if(subs(opP->con1)) {
|
||||
case 'C': /* Fixed size LONG coproc branches */
|
||||
the_ins.opcode[the_ins.numo-1]|=0x40;
|
||||
/* Offset the displacement to be relative to byte disp location */
|
||||
/* Coproc branches don't have a byte disp option, but they are
|
||||
compatible with the ordinary branches, which do... */
|
||||
opP->con1->e_exp.X_add_number+=4;
|
||||
add_fix('l',opP->con1,1);
|
||||
addword(0);
|
||||
addword(0);
|
||||
break;
|
||||
case 'c': /* Var size Coprocesssor branches */
|
||||
if(subs(opP->con1)) {
|
||||
add_fix('l',opP->con1,1);
|
||||
add_frag((symbolS *)0,(long)0,TAB(FBRANCH,LONG));
|
||||
} else if(adds(opP->con1)) {
|
||||
@ -1884,7 +1897,7 @@ char *instring;
|
||||
}
|
||||
tmpreg=get_num(opP->con1,80);
|
||||
if(!issword(tmpreg)) {
|
||||
as_bad("Expression out of range, using 0");
|
||||
as_warn("Expression out of range, using 0");
|
||||
tmpreg=0;
|
||||
}
|
||||
addword(tmpreg);
|
||||
@ -2357,7 +2370,7 @@ char *s;
|
||||
return 0;
|
||||
if(*s!=':') return 1;
|
||||
/* This kludge here is for the division cmd, which is a kludge */
|
||||
if(strchr("aAdD#",s[1])) return 0;
|
||||
if(index("aAdD#",s[1])) return 0;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
@ -2552,7 +2565,7 @@ obstack_alloc(&robyn,sizeof(struct m68_incant));
|
||||
retval = hash_insert (op_hash, ins->name,(char *)hack);
|
||||
/* Didn't his mommy tell him about null pointers? */
|
||||
if(retval && *retval)
|
||||
as_fatal("Internal Error: Can't hash %s: %s", ins->name,retval);
|
||||
as_fatal("Internal Error: Can't hash %s: %s",ins->name,retval);
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(mklower_table) ; i++)
|
||||
@ -2608,6 +2621,7 @@ int *sizeP;
|
||||
LITTLENUM_TYPE words[MAX_LITTLENUMS];
|
||||
LITTLENUM_TYPE *wordP;
|
||||
char *t;
|
||||
char *atof_ieee();
|
||||
|
||||
switch(type) {
|
||||
case 'f':
|
||||
@ -2714,21 +2728,31 @@ md_apply_fix(fixP, val)
|
||||
MAGIC here. ..
|
||||
*/
|
||||
void
|
||||
md_convert_frag(fragP)
|
||||
md_convert_frag(headers, fragP)
|
||||
object_headers *headers;
|
||||
register fragS *fragP;
|
||||
{
|
||||
long disp;
|
||||
long ext;
|
||||
|
||||
/* Address in gas core of the place to store the displacement. */
|
||||
register char *buffer_address = fragP -> fr_fix + fragP -> fr_literal;
|
||||
/* Address in object code of the displacement. */
|
||||
register int object_address = fragP -> fr_fix + fragP -> fr_address;
|
||||
|
||||
know(fragP->fr_symbol);
|
||||
#ifdef IBM_COMPILER_SUX
|
||||
/* This is wrong but it convinces the native rs6000 compiler to
|
||||
generate the code we want. */
|
||||
register char *buffer_address = fragP -> fr_literal;
|
||||
buffer_address += fragP -> fr_fix;
|
||||
#else /* IBM_COMPILER_SUX */
|
||||
/* Address in gas core of the place to store the displacement. */
|
||||
register char *buffer_address = fragP->fr_fix + fragP->fr_literal;
|
||||
#endif /* IBM_COMPILER_SUX */
|
||||
|
||||
/* No longer true: know(fragP->fr_symbol); */
|
||||
|
||||
/* The displacement of the address, from current location. */
|
||||
disp = (S_GET_VALUE(fragP->fr_symbol) + fragP->fr_offset) - object_address;
|
||||
disp = fragP->fr_symbol ? S_GET_VALUE(fragP->fr_symbol) : 0;
|
||||
disp = (disp + fragP->fr_offset) - object_address;
|
||||
|
||||
switch(fragP->fr_subtype) {
|
||||
case TAB(BCC68000,BYTE):
|
||||
@ -2753,7 +2777,7 @@ register fragS *fragP;
|
||||
if(flagseen['m']) {
|
||||
if(fragP->fr_opcode[0]==0x61) {
|
||||
fragP->fr_opcode[0]= 0x4E;
|
||||
fragP->fr_opcode[1]= 0xB9; /* JSR with ABSL LONG offset */
|
||||
fragP->fr_opcode[1]= 0xB9; /* JBSR with ABSL LONG offset */
|
||||
subseg_change(SEG_TEXT, 0);
|
||||
|
||||
fix_new(fragP,
|
||||
@ -2833,21 +2857,20 @@ register fragS *fragP;
|
||||
ext=2;
|
||||
break;
|
||||
case TAB(PCREL,LONG):
|
||||
/* FIXME-SOMEDAY, this should allow pcrel-long to be generated if -pic is on.
|
||||
Else we can't handle position independent code. Pcrel-long costs an
|
||||
extra index word though. Doing it requires more relax tables and
|
||||
stuff elsewhere in this module though. */
|
||||
/* The thing to do here is force it to ABSOLUTE LONG, since
|
||||
PCREL is really trying to shorten an ABSOLUTE address anyway */
|
||||
/* JF FOO This code has not been tested */
|
||||
subseg_change(SEG_TEXT,0);
|
||||
fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, fragP->fr_offset, 0,
|
||||
NO_RELOC);
|
||||
fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, fragP->fr_offset, 0, NO_RELOC);
|
||||
if((fragP->fr_opcode[1] & 0x3F) != 0x3A)
|
||||
as_bad("Internal error (long PC-relative operand) for insn 0x%04lx at 0x%lx",
|
||||
fragP->fr_opcode[0],fragP->fr_address);
|
||||
fragP->fr_opcode[1]&= ~0x3F;
|
||||
fragP->fr_opcode[1]|=0x39; /* Mode 7.1 */
|
||||
fragP->fr_fix+=4;
|
||||
/* md_number_to_chars(buffer_address,
|
||||
(long)(fragP->fr_symbol->sy_value + fragP->fr_offset),
|
||||
4); */
|
||||
ext=0;
|
||||
break;
|
||||
case TAB(PCLEA,SHORT):
|
||||
@ -2869,12 +2892,20 @@ register fragS *fragP;
|
||||
ext=4;
|
||||
break;
|
||||
|
||||
}
|
||||
if(ext) {
|
||||
md_number_to_chars(buffer_address,(long)disp,(int)ext);
|
||||
fragP->fr_fix+=ext;
|
||||
}
|
||||
}
|
||||
} /* switch on subtype */
|
||||
|
||||
if (ext) {
|
||||
md_number_to_chars(buffer_address, (long) disp, (int) ext);
|
||||
fragP->fr_fix += ext;
|
||||
/* H_SET_TEXT_SIZE(headers, H_GET_TEXT_SIZE(headers) + ext); */
|
||||
} /* if extending */
|
||||
|
||||
know((fragP->fr_next == NULL)
|
||||
|| ((fragP->fr_next->fr_address - fragP->fr_address)
|
||||
== (fragP->fr_fix)));
|
||||
|
||||
return;
|
||||
} /* md_convert_frag() */
|
||||
|
||||
/* Force truly undefined symbols to their maximum size, and generally set up
|
||||
the frag list to be relaxed
|
||||
@ -2890,105 +2921,10 @@ segT segment;
|
||||
|
||||
/* handle SZ_UNDEF first, it can be changed to BYTE or SHORT */
|
||||
switch(fragP->fr_subtype) {
|
||||
case TAB(BRANCH,SZ_UNDEF):
|
||||
if(S_GET_SEGMENT(fragP->fr_symbol) == segment) {
|
||||
/* Symbol now defined; start at byte-size. */
|
||||
fragP->fr_subtype=TAB(TABTYPE(fragP->fr_subtype),BYTE);
|
||||
break;
|
||||
} else if(!flagseen['p'] || (!flagseen['l'] && flagseen['m'])) {
|
||||
/* Symbol in another segment, or undef.
|
||||
If we don't care about position independent code,
|
||||
or if we're using long displacements on a 68000,
|
||||
rewrite to short or long absolute. */
|
||||
if(fragP->fr_opcode[0]==0x61) {
|
||||
if(flagseen['l']) {
|
||||
fragP->fr_opcode[0]= 0x4E;
|
||||
fragP->fr_opcode[1]= 0xB9; /* JBSR with ABSL WORD offset */
|
||||
subseg_change(SEG_TEXT, 0);
|
||||
fix_new(fragP, fragP->fr_fix, 2,
|
||||
fragP->fr_symbol, 0, fragP->fr_offset, 0,
|
||||
NO_RELOC);
|
||||
fragP->fr_fix+=2;
|
||||
} else {
|
||||
fragP->fr_opcode[0]= 0x4E;
|
||||
fragP->fr_opcode[1]= 0xB9; /* JBSR with ABSL LONG offset */
|
||||
subseg_change(SEG_TEXT, 0);
|
||||
fix_new(fragP, fragP->fr_fix, 4,
|
||||
fragP->fr_symbol, 0, fragP->fr_offset, 0,
|
||||
NO_RELOC);
|
||||
fragP->fr_fix+=4;
|
||||
}
|
||||
frag_wane(fragP);
|
||||
} else if(fragP->fr_opcode[0]==0x60) {
|
||||
if(flagseen['l']) {
|
||||
fragP->fr_opcode[0]= 0x4E;
|
||||
fragP->fr_opcode[1]= 0xF8; /* JMP with ABSL WORD offset */
|
||||
subseg_change(SEG_TEXT, 0);
|
||||
fix_new(fragP, fragP->fr_fix, 2,
|
||||
fragP->fr_symbol, 0, fragP->fr_offset, 0,
|
||||
NO_RELOC);
|
||||
fragP->fr_fix+=2;
|
||||
} else {
|
||||
fragP->fr_opcode[0]= 0x4E;
|
||||
fragP->fr_opcode[1]= 0xF9; /* JMP with ABSL LONG offset */
|
||||
subseg_change(SEG_TEXT, 0);
|
||||
fix_new(fragP, fragP->fr_fix, 4,
|
||||
fragP->fr_symbol, 0, fragP->fr_offset, 0,
|
||||
NO_RELOC);
|
||||
fragP->fr_fix+=4;
|
||||
}
|
||||
frag_wane(fragP);
|
||||
} else {
|
||||
as_bad("Long branch offset to extern symbol not supported.");
|
||||
}
|
||||
} else if(flagseen['l']) {
|
||||
/* Symbol in other seg or undefined, and user
|
||||
wants short pcrel offsets (-l). Set size to 2, fix
|
||||
pcrel displacement after relax. */
|
||||
fix_new(fragP,(int)(fragP->fr_fix),2,fragP->fr_symbol,
|
||||
(symbolS *)0,fragP->fr_offset+2,1,
|
||||
NO_RELOC);
|
||||
fragP->fr_fix+=2;
|
||||
fragP->fr_opcode[1]=0x00;
|
||||
frag_wane(fragP);
|
||||
} else {
|
||||
/* Symbol in other seg or undefined, and user
|
||||
wants long pcrel offsets. Set size to 4, and fix
|
||||
pcrel displacement after relax. */
|
||||
fix_new(fragP,(int)(fragP->fr_fix),4,fragP->fr_symbol,
|
||||
(symbolS *)0,fragP->fr_offset + 4,1,
|
||||
NO_RELOC);
|
||||
fragP->fr_fix+=4;
|
||||
fragP->fr_opcode[1]=0xff;
|
||||
frag_wane(fragP);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case TAB(FBRANCH,SZ_UNDEF):
|
||||
if(S_GET_SEGMENT(fragP->fr_symbol) == segment
|
||||
|| flagseen['l']) {
|
||||
fragP->fr_subtype=TAB(FBRANCH,SHORT);
|
||||
fragP->fr_var+=2;
|
||||
} else {
|
||||
fragP->fr_subtype=TAB(FBRANCH,LONG);
|
||||
fragP->fr_var+=4;
|
||||
}
|
||||
break;
|
||||
|
||||
case TAB(PCREL,SZ_UNDEF):
|
||||
if(S_GET_SEGMENT(fragP->fr_symbol) == segment
|
||||
|| flagseen['l']) {
|
||||
fragP->fr_subtype=TAB(PCREL,SHORT);
|
||||
fragP->fr_var+=2;
|
||||
} else {
|
||||
fragP->fr_subtype=TAB(PCREL,LONG);
|
||||
fragP->fr_var+=4;
|
||||
}
|
||||
break;
|
||||
|
||||
case TAB(BCC68000,SZ_UNDEF):
|
||||
if(S_GET_SEGMENT(fragP->fr_symbol) == segment) {
|
||||
case TAB(BCC68000,SZ_UNDEF): {
|
||||
if((fragP->fr_symbol != NULL)
|
||||
&& S_GET_SEGMENT(fragP->fr_symbol) == segment) {
|
||||
fragP->fr_subtype=TAB(BCC68000,BYTE);
|
||||
break;
|
||||
}
|
||||
@ -3003,8 +2939,7 @@ segT segment;
|
||||
fragP->fr_fix += 2; /* account for jmp instruction */
|
||||
subseg_change(SEG_TEXT,0);
|
||||
fix_new(fragP, fragP->fr_fix, 2, fragP->fr_symbol, 0,
|
||||
fragP->fr_offset,0,
|
||||
NO_RELOC);
|
||||
fragP->fr_offset, 0, NO_RELOC);
|
||||
fragP->fr_fix += 2;
|
||||
} else {
|
||||
fragP->fr_opcode[1] = 0x06; /* branch offset = 6 */
|
||||
@ -3014,15 +2949,15 @@ segT segment;
|
||||
fragP->fr_fix += 2; /* account for jmp instruction */
|
||||
subseg_change(SEG_TEXT,0);
|
||||
fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0,
|
||||
fragP->fr_offset,0,
|
||||
NO_RELOC);
|
||||
fragP->fr_offset, 0, NO_RELOC);
|
||||
fragP->fr_fix += 4;
|
||||
}
|
||||
frag_wane(fragP);
|
||||
break;
|
||||
} /* case TAB(BCC68000,SZ_UNDEF) */
|
||||
|
||||
case TAB(DBCC,SZ_UNDEF):
|
||||
if(S_GET_SEGMENT(fragP->fr_symbol) == segment) {
|
||||
case TAB(DBCC,SZ_UNDEF): {
|
||||
if (fragP->fr_symbol != NULL && S_GET_SEGMENT(fragP->fr_symbol) == segment) {
|
||||
fragP->fr_subtype=TAB(DBCC,SHORT);
|
||||
fragP->fr_var+=2;
|
||||
break;
|
||||
@ -3032,7 +2967,8 @@ segT segment;
|
||||
/* JF: these used to be fr_opcode[2-4], which is wrong. */
|
||||
buffer_address[0] = 0x00; /* branch offset = 4 */
|
||||
buffer_address[1] = 0x04;
|
||||
buffer_address[2] = 0x60; /* put in bra pc + ... */
|
||||
buffer_address[2] = 0x60; /* put in bra pc + ... */
|
||||
|
||||
if(flagseen['l']) {
|
||||
/* JF: these were fr_opcode[5-7] */
|
||||
buffer_address[3] = 0x04; /* plus 4 */
|
||||
@ -3041,9 +2977,8 @@ segT segment;
|
||||
fragP->fr_fix += 6; /* account for bra/jmp instruction */
|
||||
subseg_change(SEG_TEXT,0);
|
||||
fix_new(fragP, fragP->fr_fix, 2, fragP->fr_symbol, 0,
|
||||
fragP->fr_offset,0,
|
||||
NO_RELOC);
|
||||
fragP->fr_fix+=2;
|
||||
fragP->fr_offset, 0, NO_RELOC);
|
||||
fragP->fr_fix += 2;
|
||||
} else {
|
||||
/* JF: these were fr_opcode[5-7] */
|
||||
buffer_address[3] = 0x06; /* Plus 6 */
|
||||
@ -3052,15 +2987,53 @@ segT segment;
|
||||
fragP->fr_fix += 6; /* account for bra/jmp instruction */
|
||||
subseg_change(SEG_TEXT,0);
|
||||
fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0,
|
||||
fragP->fr_offset,0,
|
||||
NO_RELOC);
|
||||
fragP->fr_offset, 0, NO_RELOC);
|
||||
fragP->fr_fix += 4;
|
||||
}
|
||||
|
||||
frag_wane(fragP);
|
||||
break;
|
||||
} /* case TAB(DBCC,SZ_UNDEF) */
|
||||
|
||||
case TAB(PCLEA,SZ_UNDEF):
|
||||
if((S_GET_SEGMENT(fragP->fr_symbol))==segment || flagseen['l']) {
|
||||
case TAB(BRANCH,SZ_UNDEF): {
|
||||
if((fragP->fr_symbol != NULL) /* Not absolute */
|
||||
&& S_GET_SEGMENT(fragP->fr_symbol) == segment) {
|
||||
fragP->fr_subtype=TAB(TABTYPE(fragP->fr_subtype),BYTE);
|
||||
break;
|
||||
} else if((fragP->fr_symbol == 0) || flagseen['m']) {
|
||||
/* On 68000, or for absolute value, switch to abs long */
|
||||
/* FIXME, we should check abs val, pick short or long */
|
||||
if(fragP->fr_opcode[0]==0x61) {
|
||||
fragP->fr_opcode[0]= 0x4E;
|
||||
fragP->fr_opcode[1]= 0xB9; /* JBSR with ABSL LONG offset */
|
||||
subseg_change(SEG_TEXT, 0);
|
||||
fix_new(fragP, fragP->fr_fix, 4,
|
||||
fragP->fr_symbol, 0, fragP->fr_offset, 0, NO_RELOC);
|
||||
fragP->fr_fix+=4;
|
||||
frag_wane(fragP);
|
||||
} else if(fragP->fr_opcode[0]==0x60) {
|
||||
fragP->fr_opcode[0]= 0x4E;
|
||||
fragP->fr_opcode[1]= 0xF9; /* JMP with ABSL LONG offset */
|
||||
subseg_change(SEG_TEXT, 0);
|
||||
fix_new(fragP, fragP->fr_fix, 4,
|
||||
fragP->fr_symbol, 0, fragP->fr_offset, 0, NO_RELOC);
|
||||
fragP->fr_fix+=4;
|
||||
frag_wane(fragP);
|
||||
} else {
|
||||
as_warn("Long branch offset to extern symbol not supported.");
|
||||
}
|
||||
} else { /* Symbol is still undefined. Make it simple */
|
||||
fix_new(fragP, (int)(fragP->fr_fix), 4, fragP->fr_symbol,
|
||||
(symbolS *)0, fragP->fr_offset+4, 1, NO_RELOC);
|
||||
fragP->fr_fix+=4;
|
||||
fragP->fr_opcode[1]=0xff;
|
||||
frag_wane(fragP);
|
||||
break;
|
||||
}
|
||||
} /* case TAB(BRANCH,SZ_UNDEF) */
|
||||
|
||||
case TAB(PCLEA,SZ_UNDEF): {
|
||||
if ((S_GET_SEGMENT(fragP->fr_symbol))==segment || flagseen['l']) {
|
||||
fragP->fr_subtype=TAB(PCLEA,SHORT);
|
||||
fragP->fr_var+=2;
|
||||
} else {
|
||||
@ -3068,6 +3041,18 @@ segT segment;
|
||||
fragP->fr_var+=6;
|
||||
}
|
||||
break;
|
||||
} /* TAB(PCLEA,SZ_UNDEF) */
|
||||
|
||||
case TAB(PCREL,SZ_UNDEF): {
|
||||
if(S_GET_SEGMENT(fragP->fr_symbol) == segment || flagseen['l']) {
|
||||
fragP->fr_subtype = TAB(PCREL,SHORT);
|
||||
fragP->fr_var += 2;
|
||||
} else {
|
||||
fragP->fr_subtype = TAB(PCREL,LONG);
|
||||
fragP->fr_var += 4;
|
||||
}
|
||||
break;
|
||||
} /* TAB(PCREL,SZ_UNDEF) */
|
||||
|
||||
default:
|
||||
break;
|
||||
@ -3079,7 +3064,7 @@ segT segment;
|
||||
case TAB(BRANCH,BYTE):
|
||||
/* We can't do a short jump to the next instruction,
|
||||
so we force word mode. */
|
||||
if(fragP->fr_symbol && S_GET_VALUE(fragP->fr_symbol)==0 &&
|
||||
if (fragP->fr_symbol && S_GET_VALUE(fragP->fr_symbol)==0 &&
|
||||
fragP->fr_symbol->sy_frag==fragP->fr_next) {
|
||||
fragP->fr_subtype=TAB(TABTYPE(fragP->fr_subtype),SHORT);
|
||||
fragP->fr_var+=2;
|
||||
@ -3148,7 +3133,7 @@ symbolS *to_symbol;
|
||||
{
|
||||
long offset;
|
||||
|
||||
if(flagseen['m']) {
|
||||
if (flagseen['m']) {
|
||||
offset=to_addr-S_GET_VALUE(to_symbol);
|
||||
md_number_to_chars(ptr ,(long)0x4EF9,2);
|
||||
md_number_to_chars(ptr+2,(long)offset,4);
|
||||
@ -3207,7 +3192,7 @@ int ok;
|
||||
adds(exp)=0;
|
||||
subs(exp)=0;
|
||||
offs(exp)= (ok==10) ? 1 : 0;
|
||||
as_bad("Null expression defaults to %ld", offs(exp));
|
||||
as_warn("Null expression defaults to %ld",offs(exp));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3229,7 +3214,7 @@ int ok;
|
||||
exp->e_siz=3;
|
||||
break;
|
||||
default:
|
||||
as_bad("Unknown size for expression \"%c\"", exp->e_end[0]);
|
||||
as_bad("Unknown size for expression \"%c\"",exp->e_end[0]);
|
||||
}
|
||||
exp->e_end-=2;
|
||||
}
|
||||
@ -3243,7 +3228,7 @@ int ok;
|
||||
adds(exp)=0;
|
||||
subs(exp)=0;
|
||||
offs(exp)= (ok==10) ? 1 : 0;
|
||||
as_bad("Unknown expression: '%s' defaulting to %d",exp->e_beg,offs(exp));
|
||||
as_warn("Unknown expression: '%s' defaulting to %d",exp->e_beg,offs(exp));
|
||||
break;
|
||||
|
||||
case SEG_ABSENT:
|
||||
@ -3253,7 +3238,7 @@ int ok;
|
||||
subs(exp)=0;
|
||||
offs(exp)=0;
|
||||
if(ok==10) {
|
||||
as_bad("expression out of range: defaulting to 1");
|
||||
as_warn("expression out of range: defaulting to 1");
|
||||
offs(exp)=1;
|
||||
}
|
||||
break;
|
||||
@ -3261,7 +3246,7 @@ int ok;
|
||||
switch(ok) {
|
||||
case 10:
|
||||
if(offs(exp)<1 || offs(exp)>8) {
|
||||
as_bad("expression out of range: defaulting to 1");
|
||||
as_warn("expression out of range: defaulting to 1");
|
||||
offs(exp)=1;
|
||||
}
|
||||
break;
|
||||
@ -3292,7 +3277,7 @@ int ok;
|
||||
case 70:
|
||||
if(offs(exp)<0 || offs(exp)>4095) {
|
||||
outrange:
|
||||
as_bad("expression out of range: defaulting to 0");
|
||||
as_warn("expression out of range: defaulting to 0");
|
||||
offs(exp)=0;
|
||||
}
|
||||
break;
|
||||
@ -3310,7 +3295,7 @@ int ok;
|
||||
adds(exp)=0;
|
||||
subs(exp)=0;
|
||||
offs(exp)= (ok==10) ? 1 : 0;
|
||||
as_bad("Can't deal with expression \"%s\": defaulting to %ld",exp->e_beg,offs(exp));
|
||||
as_warn("Can't deal with expression \"%s\": defaulting to %ld",exp->e_beg,offs(exp));
|
||||
}
|
||||
break;
|
||||
case SEG_BIG:
|
||||
@ -3327,7 +3312,7 @@ int ok;
|
||||
adds(exp)=0;
|
||||
subs(exp)=0;
|
||||
offs(exp)= (ok==10) ? 1 : 0;
|
||||
as_bad("Can't deal with expression \"%s\": defaulting to %ld",exp->e_beg,offs(exp));
|
||||
as_warn("Can't deal with expression \"%s\": defaulting to %ld",exp->e_beg,offs(exp));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -3341,11 +3326,11 @@ int ok;
|
||||
switch(exp->e_siz) {
|
||||
case 1:
|
||||
if(!isbyte(offs(exp)))
|
||||
as_bad("expression doesn't fit in BYTE");
|
||||
as_warn("expression doesn't fit in BYTE");
|
||||
break;
|
||||
case 2:
|
||||
if(!isword(offs(exp)))
|
||||
as_bad("expression doesn't fit in WORD");
|
||||
as_warn("expression doesn't fit in WORD");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -3354,6 +3339,7 @@ int ok;
|
||||
} /* get_num() */
|
||||
|
||||
/* These are the back-ends for the various machine dependent pseudo-ops. */
|
||||
void demand_empty_rest_of_line(); /* Hate those extra verbose names */
|
||||
|
||||
static void s_data1() {
|
||||
subseg_new(SEG_DATA,1);
|
||||
@ -3396,8 +3382,8 @@ int *cntP;
|
||||
char ***vecP;
|
||||
{
|
||||
switch(**argP) {
|
||||
case 'l': /* -l means keep externals to 2 byte branch offsets
|
||||
rather than 4 byte branch offsets */
|
||||
case 'l': /* -l means keep external to 2 bit offset
|
||||
rather than 16 bit one */
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
@ -3409,7 +3395,7 @@ char ***vecP;
|
||||
flagseen['m']=2;
|
||||
else if(!strcmp(*argP,"68010")) {
|
||||
#ifdef TE_SUN
|
||||
magic_number_for_object_file = 1<<16|OMAGIC;
|
||||
omagic= 1<<16|OMAGIC;
|
||||
#endif
|
||||
flagseen['m']=1;
|
||||
} else if(!strcmp(*argP,"68020"))
|
||||
@ -3619,7 +3605,7 @@ This file is part of GDB, the GNU Debugger and GAS, the GNU Assembler.
|
||||
|
||||
Both GDB and GAS are free software; you can redistribute and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GDB and GAS are distributed in the hope that it will be useful,
|
||||
|
708
gas/write.c
708
gas/write.c
@ -5,7 +5,7 @@ This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful,
|
||||
@ -115,7 +115,6 @@ enum reloc_type r_type; /* Relocation type */
|
||||
fixP->fx_offset = offset;
|
||||
fixP->fx_pcrel = pcrel;
|
||||
fixP->fx_r_type = r_type;
|
||||
fixP->fx_next = NULL;
|
||||
|
||||
/* JF these 'cuz of the NS32K stuff */
|
||||
fixP->fx_im_disp = 0;
|
||||
@ -123,15 +122,32 @@ enum reloc_type r_type; /* Relocation type */
|
||||
fixP->fx_bsr = 0;
|
||||
fixP->fx_bit_fixP = 0;
|
||||
|
||||
/* usually, we want relocs sorted numerically, but while
|
||||
comparing to older versions of gas that have relocs
|
||||
reverse sorted, it is convenient to have this compile
|
||||
time option. xoxorich. */
|
||||
|
||||
#ifdef REVERSE_SORT_RELOCS
|
||||
|
||||
fixP->fx_next = *seg_fix_rootP;
|
||||
*seg_fix_rootP = fixP;
|
||||
|
||||
#else /* REVERSE_SORT_RELOCS */
|
||||
|
||||
fixP->fx_next = NULL;
|
||||
|
||||
if (*seg_fix_tailP)
|
||||
(*seg_fix_tailP)->fx_next = fixP;
|
||||
else
|
||||
*seg_fix_rootP = fixP;
|
||||
*seg_fix_tailP = fixP;
|
||||
|
||||
#endif /* REVERSE_SORT_RELOCS */
|
||||
|
||||
fixP->fx_callj = 0;
|
||||
return fixP;
|
||||
}
|
||||
|
||||
|
||||
void write_object_file() {
|
||||
register struct frchain * frchainP; /* Track along all frchains. */
|
||||
register fragS * fragP; /* Track along all frags. */
|
||||
@ -190,7 +206,7 @@ void write_object_file() {
|
||||
/* know( frags . obstack_c_base == frags . obstack_c_next_free ); */
|
||||
/* Above shows we haven't left a half-completed object on obstack. */
|
||||
} /* walk the frag chain */
|
||||
|
||||
|
||||
/*
|
||||
* From now on, we don't care about sub-segments.
|
||||
* Build one frag chain for each segment. Linked thru fr_next.
|
||||
@ -240,8 +256,8 @@ void write_object_file() {
|
||||
*/
|
||||
|
||||
know(text_last_frag->fr_type == rs_fill && text_last_frag->fr_offset == 0);
|
||||
H_SET_TEXT_SIZE(&headers,text_last_frag->fr_address);
|
||||
text_last_frag->fr_address=H_GET_TEXT_SIZE(&headers);
|
||||
H_SET_TEXT_SIZE(&headers, text_last_frag->fr_address);
|
||||
text_last_frag->fr_address = H_GET_TEXT_SIZE(&headers);
|
||||
|
||||
/*
|
||||
* Join the 2 segments into 1 huge segment.
|
||||
@ -251,20 +267,20 @@ void write_object_file() {
|
||||
* Determine a_data [length of data segment].
|
||||
*/
|
||||
if (data_frag_root) {
|
||||
register relax_addressT slide;
|
||||
register relax_addressT slide;
|
||||
|
||||
know( text_last_frag->fr_type == rs_fill && text_last_frag->fr_offset == 0 );
|
||||
know((text_last_frag->fr_type == rs_fill)
|
||||
&& (text_last_frag->fr_offset == 0));
|
||||
|
||||
H_SET_DATA_SIZE(&headers, data_last_frag->fr_address);
|
||||
data_last_frag->fr_address = H_GET_DATA_SIZE(&headers);
|
||||
slide = H_GET_TEXT_SIZE(&headers); /* & in file of the data segment. */
|
||||
|
||||
for (fragP = data_frag_root;
|
||||
fragP;
|
||||
fragP = fragP->fr_next)
|
||||
{
|
||||
fragP->fr_address += slide;
|
||||
}
|
||||
know( text_last_frag );
|
||||
for (fragP = data_frag_root; fragP; fragP = fragP->fr_next) {
|
||||
fragP->fr_address += slide;
|
||||
} /* for each data frag */
|
||||
|
||||
know(text_last_frag != 0);
|
||||
text_last_frag->fr_next = data_frag_root;
|
||||
} else {
|
||||
H_SET_DATA_SIZE(&headers,0);
|
||||
@ -321,25 +337,25 @@ void write_object_file() {
|
||||
case rs_align:
|
||||
case rs_org:
|
||||
fragP->fr_type = rs_fill;
|
||||
know( fragP->fr_var == 1 );
|
||||
know( fragP->fr_next );
|
||||
fragP->fr_offset
|
||||
= fragP->fr_next->fr_address
|
||||
- fragP->fr_address
|
||||
- fragP->fr_fix;
|
||||
know(fragP->fr_var == 1);
|
||||
know(fragP->fr_next != NULL);
|
||||
|
||||
fragP->fr_offset = (fragP->fr_next->fr_address
|
||||
- fragP->fr_address
|
||||
- fragP->fr_fix);
|
||||
break;
|
||||
|
||||
case rs_fill:
|
||||
break;
|
||||
|
||||
case rs_machine_dependent:
|
||||
md_convert_frag (fragP);
|
||||
md_convert_frag(&headers, fragP);
|
||||
/*
|
||||
* After md_convert_frag, we make the frag into a ".space 0".
|
||||
* Md_convert_frag() should set up any fixSs and constants
|
||||
* required.
|
||||
*/
|
||||
frag_wane (fragP);
|
||||
frag_wane(fragP);
|
||||
break;
|
||||
|
||||
#ifndef WORKING_DOT_WORD
|
||||
@ -463,13 +479,13 @@ void write_object_file() {
|
||||
|
||||
/* FIXME move this stuff into the pre-write-hook */
|
||||
H_SET_MAGIC_NUMBER(&headers, magic_number_for_object_file);
|
||||
H_SET_ENTRY_POINT(&headers,0);
|
||||
H_SET_ENTRY_POINT(&headers, 0);
|
||||
|
||||
#ifdef EXEC_MACHINE_TYPE
|
||||
H_SET_MACHINE_TYPE(&headers,EXEC_MACHINE_TYPE);
|
||||
H_SET_MACHINE_TYPE(&headers, EXEC_MACHINE_TYPE);
|
||||
#endif
|
||||
#ifdef EXEC_VERSION
|
||||
H_SET_VERSION(&headers,EXEC_VERSION);
|
||||
H_SET_VERSION(&headers, EXEC_VERSION);
|
||||
#endif
|
||||
|
||||
obj_pre_write_hook(&headers); /* extra coff stuff */
|
||||
@ -493,29 +509,42 @@ void write_object_file() {
|
||||
output_file_create(out_file_name);
|
||||
|
||||
obj_header_append(&next_object_file_charP, &headers);
|
||||
|
||||
know((next_object_file_charP - the_object_file) == H_GET_HEADER_SIZE(&headers));
|
||||
|
||||
/*
|
||||
* Emit code.
|
||||
*/
|
||||
for (fragP = text_frag_root; fragP; fragP = fragP->fr_next) {
|
||||
register long count;
|
||||
register char * fill_literal;
|
||||
register long fill_size;
|
||||
register long count;
|
||||
register char *fill_literal;
|
||||
register long fill_size;
|
||||
|
||||
know( fragP->fr_type == rs_fill );
|
||||
append (& next_object_file_charP, fragP->fr_literal, (unsigned long)fragP->fr_fix);
|
||||
fill_literal= fragP->fr_literal + fragP->fr_fix;
|
||||
fill_size = fragP->fr_var;
|
||||
know( fragP->fr_offset >= 0 );
|
||||
for (count = fragP->fr_offset; count; count --)
|
||||
append (& next_object_file_charP, fill_literal, (unsigned long)fill_size);
|
||||
know(fragP->fr_type == rs_fill);
|
||||
append(&next_object_file_charP, fragP->fr_literal, (unsigned long) fragP->fr_fix);
|
||||
fill_literal = fragP->fr_literal + fragP->fr_fix;
|
||||
fill_size = fragP->fr_var;
|
||||
know(fragP->fr_offset >= 0);
|
||||
|
||||
for (count = fragP->fr_offset; count; count--) {
|
||||
append(&next_object_file_charP, fill_literal, (unsigned long) fill_size);
|
||||
} /* for each */
|
||||
|
||||
} /* for each code frag. */
|
||||
|
||||
know((next_object_file_charP - the_object_file)
|
||||
== (H_GET_HEADER_SIZE(&headers)
|
||||
+ H_GET_TEXT_SIZE(&headers)
|
||||
+ H_GET_DATA_SIZE(&headers)));
|
||||
|
||||
/*
|
||||
* Emit relocations.
|
||||
*/
|
||||
obj_emit_relocations(&next_object_file_charP, text_fix_root, (relax_addressT)0);
|
||||
|
||||
know((next_object_file_charP - the_object_file)
|
||||
== (H_GET_HEADER_SIZE(&headers)
|
||||
+ H_GET_TEXT_SIZE(&headers)
|
||||
+ H_GET_DATA_SIZE(&headers)
|
||||
+ H_GET_TEXT_RELOCATION_SIZE(&headers)));
|
||||
#ifdef TC_I960
|
||||
/* Make addresses in data relocation directives relative to beginning of
|
||||
* first data fragment, not end of last text fragment: alignment of the
|
||||
@ -526,16 +555,38 @@ void write_object_file() {
|
||||
obj_emit_relocations(&next_object_file_charP, data_fix_root, text_last_frag->fr_address);
|
||||
#endif /* TC_I960 */
|
||||
|
||||
know((next_object_file_charP - the_object_file)
|
||||
== (H_GET_HEADER_SIZE(&headers)
|
||||
+ H_GET_TEXT_SIZE(&headers)
|
||||
+ H_GET_DATA_SIZE(&headers)
|
||||
+ H_GET_TEXT_RELOCATION_SIZE(&headers)
|
||||
+ H_GET_DATA_RELOCATION_SIZE(&headers)));
|
||||
|
||||
/*
|
||||
* Emit line number entries.
|
||||
*/
|
||||
OBJ_EMIT_LINENO(&next_object_file_charP, lineno_rootP, the_object_file);
|
||||
know((next_object_file_charP - the_object_file)
|
||||
== (H_GET_HEADER_SIZE(&headers)
|
||||
+ H_GET_TEXT_SIZE(&headers)
|
||||
+ H_GET_DATA_SIZE(&headers)
|
||||
+ H_GET_TEXT_RELOCATION_SIZE(&headers)
|
||||
+ H_GET_DATA_RELOCATION_SIZE(&headers)
|
||||
+ H_GET_LINENO_SIZE(&headers)));
|
||||
|
||||
/*
|
||||
* Emit symbols.
|
||||
*/
|
||||
obj_emit_symbols(&next_object_file_charP, symbol_rootP);
|
||||
|
||||
know((next_object_file_charP - the_object_file)
|
||||
== (H_GET_HEADER_SIZE(&headers)
|
||||
+ H_GET_TEXT_SIZE(&headers)
|
||||
+ H_GET_DATA_SIZE(&headers)
|
||||
+ H_GET_TEXT_RELOCATION_SIZE(&headers)
|
||||
+ H_GET_DATA_RELOCATION_SIZE(&headers)
|
||||
+ H_GET_LINENO_SIZE(&headers)
|
||||
+ H_GET_SYMBOL_TABLE_SIZE(&headers)));
|
||||
|
||||
/*
|
||||
* Emit strings.
|
||||
*/
|
||||
@ -544,6 +595,16 @@ void write_object_file() {
|
||||
obj_emit_strings(&next_object_file_charP);
|
||||
} /* only if we have a string table */
|
||||
|
||||
know((next_object_file_charP - the_object_file)
|
||||
== (H_GET_HEADER_SIZE(&headers)
|
||||
+ H_GET_TEXT_SIZE(&headers)
|
||||
+ H_GET_DATA_SIZE(&headers)
|
||||
+ H_GET_TEXT_RELOCATION_SIZE(&headers)
|
||||
+ H_GET_DATA_RELOCATION_SIZE(&headers)
|
||||
+ H_GET_LINENO_SIZE(&headers)
|
||||
+ H_GET_SYMBOL_TABLE_SIZE(&headers)
|
||||
+ H_GET_STRING_SIZE(&headers)));
|
||||
|
||||
know(next_object_file_charP == the_object_file + object_file_size);
|
||||
/* Write the data to the file */
|
||||
output_file_append(the_object_file,object_file_size,out_file_name);
|
||||
@ -581,303 +642,297 @@ void write_object_file() {
|
||||
#ifndef VMS
|
||||
static
|
||||
#endif /* not VMS */
|
||||
void relax_segment(segment_frag_root, segment_type)
|
||||
void relax_segment(segment_frag_root, segment)
|
||||
struct frag * segment_frag_root;
|
||||
segT segment_type; /* SEG_DATA or SEG_TEXT */
|
||||
segT segment; /* SEG_DATA or SEG_TEXT */
|
||||
{
|
||||
register struct frag * fragP;
|
||||
register relax_addressT address;
|
||||
/* register relax_addressT old_address; JF unused */
|
||||
/* register relax_addressT new_address; JF unused */
|
||||
|
||||
know( segment_type == SEG_DATA || segment_type == SEG_TEXT );
|
||||
|
||||
/* In case md_estimate_size_before_relax() wants to make fixSs. */
|
||||
subseg_change(segment_type, 0);
|
||||
|
||||
/*
|
||||
* For each frag in segment: count and store (a 1st guess of) fr_address.
|
||||
*/
|
||||
address = 0;
|
||||
for ( fragP = segment_frag_root; fragP; fragP = fragP->fr_next )
|
||||
{
|
||||
fragP->fr_address = address;
|
||||
address += fragP->fr_fix;
|
||||
switch (fragP->fr_type)
|
||||
register struct frag * fragP;
|
||||
register relax_addressT address;
|
||||
/* register relax_addressT old_address; JF unused */
|
||||
/* register relax_addressT new_address; JF unused */
|
||||
|
||||
know( segment == SEG_DATA || segment == SEG_TEXT );
|
||||
|
||||
/* In case md_estimate_size_before_relax() wants to make fixSs. */
|
||||
subseg_change(segment, 0);
|
||||
|
||||
/*
|
||||
* For each frag in segment: count and store (a 1st guess of) fr_address.
|
||||
*/
|
||||
address = 0;
|
||||
for (fragP = segment_frag_root; fragP; fragP = fragP->fr_next) {
|
||||
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:
|
||||
address += relax_align(address, fragP->fr_offset);
|
||||
break;
|
||||
|
||||
case rs_org:
|
||||
/*
|
||||
* Assume .org is nugatory. It will grow with 1st relax.
|
||||
*/
|
||||
break;
|
||||
|
||||
case rs_machine_dependent:
|
||||
address += md_estimate_size_before_relax(fragP, segment);
|
||||
break;
|
||||
|
||||
#ifndef WORKING_DOT_WORD
|
||||
/* Broken words don't concern us yet */
|
||||
case rs_broken_word:
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
BAD_CASE(fragP->fr_type);
|
||||
break;
|
||||
} /* switch(fr_type) */
|
||||
} /* for each frag in the segment */
|
||||
|
||||
/*
|
||||
* Do relax().
|
||||
*/
|
||||
{
|
||||
case rs_fill:
|
||||
address += fragP->fr_offset * fragP->fr_var;
|
||||
break;
|
||||
|
||||
case rs_align:
|
||||
address += relax_align(address, fragP->fr_offset);
|
||||
break;
|
||||
|
||||
case rs_org:
|
||||
/*
|
||||
* Assume .org is nugatory. It will grow with 1st relax.
|
||||
*/
|
||||
break;
|
||||
|
||||
case rs_machine_dependent:
|
||||
address += md_estimate_size_before_relax(fragP, segment_type);
|
||||
break;
|
||||
register long stretch; /* May be any size, 0 or negative. */
|
||||
/* Cumulative number of addresses we have */
|
||||
/* relaxed this pass. */
|
||||
/* We may have relaxed more than one address. */
|
||||
register long stretched; /* Have we stretched on this pass? */
|
||||
/* This is 'cuz stretch may be zero, when,
|
||||
in fact some piece of code grew, and
|
||||
another shrank. If a branch instruction
|
||||
doesn't fit anymore, we could be scrod */
|
||||
|
||||
do {
|
||||
stretch = stretched = 0;
|
||||
for (fragP = segment_frag_root; fragP; fragP = fragP->fr_next) {
|
||||
register long growth = 0;
|
||||
register unsigned long was_address;
|
||||
/* register long var; */
|
||||
register long offset;
|
||||
register symbolS *symbolP;
|
||||
register long target;
|
||||
register long after;
|
||||
register long aim;
|
||||
|
||||
was_address = fragP->fr_address;
|
||||
address = fragP->fr_address += stretch;
|
||||
symbolP = fragP->fr_symbol;
|
||||
offset = fragP->fr_offset;
|
||||
/* var = fragP->fr_var; */
|
||||
|
||||
switch (fragP->fr_type) {
|
||||
case rs_fill: /* .fill never relaxes. */
|
||||
growth = 0;
|
||||
break;
|
||||
|
||||
#ifndef WORKING_DOT_WORD
|
||||
/* Broken words don't concern us yet */
|
||||
case rs_broken_word:
|
||||
break;
|
||||
#endif
|
||||
/* JF: This is RMS's idea. I do *NOT* want to be blamed
|
||||
for it I do not want to write it. I do not want to have
|
||||
anything to do with it. This is not the proper way to
|
||||
implement this misfeature. */
|
||||
case rs_broken_word: {
|
||||
struct broken_word *lie;
|
||||
struct broken_word *untruth;
|
||||
extern int md_short_jump_size;
|
||||
extern int md_long_jump_size;
|
||||
|
||||
/* Yes this is ugly (storing the broken_word pointer
|
||||
in the symbol slot). Still, this whole chunk of
|
||||
code is ugly, and I don't feel like doing anything
|
||||
about it. Think of it as stubbornness in action */
|
||||
growth=0;
|
||||
for (lie=(struct broken_word *)(fragP->fr_symbol);
|
||||
lie && lie->dispfrag==fragP;
|
||||
lie=lie->next_broken_word) {
|
||||
|
||||
if (lie->added)
|
||||
continue;
|
||||
|
||||
default:
|
||||
BAD_CASE( fragP->fr_type );
|
||||
break;
|
||||
} /* switch(fr_type) */
|
||||
} /* for each frag in the segment */
|
||||
|
||||
/*
|
||||
* Do relax().
|
||||
*/
|
||||
{
|
||||
register long stretch; /* May be any size, 0 or negative. */
|
||||
/* Cumulative number of addresses we have */
|
||||
/* relaxed this pass. */
|
||||
/* We may have relaxed more than one address. */
|
||||
register long stretched; /* Have we stretched on this pass? */
|
||||
/* This is 'cuz stretch may be zero, when,
|
||||
in fact some piece of code grew, and
|
||||
another shrank. If a branch instruction
|
||||
doesn't fit anymore, we could be scrod */
|
||||
|
||||
do
|
||||
{
|
||||
stretch = stretched = 0;
|
||||
for (fragP = segment_frag_root; fragP; fragP = fragP->fr_next)
|
||||
{
|
||||
register long growth = 0;
|
||||
register unsigned long was_address;
|
||||
/* register long var; */
|
||||
register long offset;
|
||||
register symbolS *symbolP;
|
||||
register long target;
|
||||
register long after;
|
||||
register long aim;
|
||||
|
||||
was_address = fragP->fr_address;
|
||||
address = fragP->fr_address += stretch;
|
||||
symbolP = fragP->fr_symbol;
|
||||
offset = fragP->fr_offset;
|
||||
/* var = fragP->fr_var; */
|
||||
switch (fragP->fr_type)
|
||||
{
|
||||
case rs_fill: /* .fill never relaxes. */
|
||||
growth = 0;
|
||||
break;
|
||||
|
||||
#ifndef WORKING_DOT_WORD
|
||||
/* JF: This is RMS's idea. I do *NOT* want to be blamed
|
||||
for it I do not want to write it. I do not want to have
|
||||
anything to do with it. This is not the proper way to
|
||||
implement this misfeature. */
|
||||
case rs_broken_word:
|
||||
{
|
||||
struct broken_word *lie;
|
||||
struct broken_word *untruth;
|
||||
extern int md_short_jump_size;
|
||||
extern int md_long_jump_size;
|
||||
|
||||
/* Yes this is ugly (storing the broken_word pointer
|
||||
in the symbol slot). Still, this whole chunk of
|
||||
code is ugly, and I don't feel like doing anything
|
||||
about it. Think of it as stubbornness in action */
|
||||
growth=0;
|
||||
for (lie=(struct broken_word *)(fragP->fr_symbol);
|
||||
lie && lie->dispfrag==fragP;
|
||||
lie=lie->next_broken_word) {
|
||||
|
||||
if (lie->added)
|
||||
continue;
|
||||
offset= lie->add->sy_frag->fr_address+ S_GET_VALUE(lie->add) + lie->addnum -
|
||||
(lie->sub->sy_frag->fr_address+ S_GET_VALUE(lie->sub));
|
||||
if (offset<=-32768 || offset>=32767) {
|
||||
if (flagseen['k'])
|
||||
as_warn(".word %s-%s+%ld didn't fit",
|
||||
S_GET_NAME(lie->add),
|
||||
S_GET_NAME(lie->sub),
|
||||
lie->addnum);
|
||||
lie->added=1;
|
||||
if (fragP->fr_subtype==0) {
|
||||
fragP->fr_subtype++;
|
||||
growth+=md_short_jump_size;
|
||||
}
|
||||
for (untruth=lie->next_broken_word;untruth && untruth->dispfrag==lie->dispfrag;untruth=untruth->next_broken_word)
|
||||
if ((untruth->add->sy_frag == lie->add->sy_frag)
|
||||
&& S_GET_VALUE(untruth->add) == S_GET_VALUE(lie->add)) {
|
||||
untruth->added=2;
|
||||
untruth->use_jump=lie;
|
||||
offset= lie->add->sy_frag->fr_address+ S_GET_VALUE(lie->add) + lie->addnum -
|
||||
(lie->sub->sy_frag->fr_address+ S_GET_VALUE(lie->sub));
|
||||
if (offset<=-32768 || offset>=32767) {
|
||||
if (flagseen['k'])
|
||||
as_warn(".word %s-%s+%ld didn't fit",
|
||||
S_GET_NAME(lie->add),
|
||||
S_GET_NAME(lie->sub),
|
||||
lie->addnum);
|
||||
lie->added=1;
|
||||
if (fragP->fr_subtype==0) {
|
||||
fragP->fr_subtype++;
|
||||
growth+=md_short_jump_size;
|
||||
}
|
||||
for (untruth=lie->next_broken_word;untruth && untruth->dispfrag==lie->dispfrag;untruth=untruth->next_broken_word)
|
||||
if ((untruth->add->sy_frag == lie->add->sy_frag)
|
||||
&& S_GET_VALUE(untruth->add) == S_GET_VALUE(lie->add)) {
|
||||
untruth->added=2;
|
||||
untruth->use_jump=lie;
|
||||
}
|
||||
growth+=md_long_jump_size;
|
||||
}
|
||||
}
|
||||
growth+=md_long_jump_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
break;
|
||||
} /* case rs_broken_word */
|
||||
#endif
|
||||
case rs_align:
|
||||
growth = relax_align ((relax_addressT)(address + fragP->fr_fix), offset)
|
||||
- relax_align ((relax_addressT)(was_address + fragP->fr_fix), offset);
|
||||
break;
|
||||
case rs_align:
|
||||
growth = relax_align((relax_addressT) (address + fragP->fr_fix), offset)
|
||||
- relax_align((relax_addressT) (was_address + fragP->fr_fix), offset);
|
||||
break;
|
||||
|
||||
case rs_org:
|
||||
target = offset;
|
||||
|
||||
case rs_org:
|
||||
target = offset;
|
||||
if (symbolP)
|
||||
{
|
||||
know((S_GET_SEGMENT(symbolP) == SEG_ABSOLUTE) ||
|
||||
(S_GET_SEGMENT(symbolP) == SEG_DATA) ||
|
||||
(S_GET_SEGMENT(symbolP) == SEG_TEXT));
|
||||
know(symbolP->sy_frag);
|
||||
know(!(S_GET_SEGMENT(symbolP) == SEG_ABSOLUTE) ||
|
||||
symbolP->sy_frag==&zero_address_frag );
|
||||
target +=
|
||||
S_GET_VALUE(symbolP)
|
||||
+ symbolP->sy_frag->fr_address;
|
||||
}
|
||||
know( fragP->fr_next );
|
||||
after = fragP->fr_next->fr_address;
|
||||
growth = ((target - after ) > 0) ? (target - after) : 0;
|
||||
/* Growth may be -ve, but variable part */
|
||||
/* of frag cannot have < 0 chars. */
|
||||
/* That is, we can't .org backwards. */
|
||||
if (symbolP) {
|
||||
know((S_GET_SEGMENT(symbolP) == SEG_ABSOLUTE)
|
||||
|| (S_GET_SEGMENT(symbolP) == SEG_DATA)
|
||||
|| (S_GET_SEGMENT(symbolP) == SEG_TEXT));
|
||||
know(symbolP->sy_frag);
|
||||
know(!(S_GET_SEGMENT(symbolP) == SEG_ABSOLUTE)
|
||||
|| (symbolP->sy_frag == &zero_address_frag));
|
||||
target += S_GET_VALUE(symbolP)
|
||||
+ symbolP->sy_frag->fr_address;
|
||||
} /* if we have a symbol */
|
||||
|
||||
growth -= stretch; /* This is an absolute growth factor */
|
||||
break;
|
||||
know(fragP->fr_next);
|
||||
after = fragP->fr_next->fr_address;
|
||||
growth = ((target - after ) > 0) ? (target - after) : 0;
|
||||
/* Growth may be -ve, but variable part */
|
||||
/* of frag cannot have < 0 chars. */
|
||||
/* That is, we can't .org backwards. */
|
||||
|
||||
growth -= stretch; /* This is an absolute growth factor */
|
||||
break;
|
||||
|
||||
case rs_machine_dependent: {
|
||||
register const relax_typeS * this_type;
|
||||
register const relax_typeS * start_type;
|
||||
register relax_substateT next_state;
|
||||
register relax_substateT this_state;
|
||||
|
||||
start_type = this_type = md_relax_table + (this_state = fragP->fr_subtype);
|
||||
target = offset;
|
||||
|
||||
case rs_machine_dependent:
|
||||
{
|
||||
register const relax_typeS * this_type;
|
||||
register const relax_typeS * start_type;
|
||||
register relax_substateT next_state;
|
||||
register relax_substateT this_state;
|
||||
if (symbolP) {
|
||||
know((S_GET_SEGMENT(symbolP) == SEG_ABSOLUTE) ||
|
||||
(S_GET_SEGMENT(symbolP) == SEG_DATA) ||
|
||||
(S_GET_SEGMENT(symbolP) == SEG_TEXT));
|
||||
know(symbolP->sy_frag);
|
||||
know(!(S_GET_SEGMENT(symbolP) == SEG_ABSOLUTE) ||
|
||||
symbolP->sy_frag==&zero_address_frag );
|
||||
target +=
|
||||
S_GET_VALUE(symbolP)
|
||||
+ symbolP->sy_frag->fr_address;
|
||||
|
||||
/* If frag has yet to be reached on this pass,
|
||||
assume it will move by STRETCH just as we did.
|
||||
If this is not so, it will be because some frag
|
||||
between grows, and that will force another pass. */
|
||||
|
||||
/* JF was just address */
|
||||
/* JF also added is_dnrange hack */
|
||||
/* There's gotta be a better/faster/etc way
|
||||
to do this. . . */
|
||||
/* gnu@cygnus.com: I changed this from > to >=
|
||||
because I ran into a zero-length frag (fr_fix=0)
|
||||
which was created when the obstack needed a new
|
||||
chunk JUST AFTER the opcode of a branch. Since
|
||||
fr_fix is zero, fr_address of this frag is the same
|
||||
as fr_address of the next frag. This
|
||||
zero-length frag was variable and jumped to .+2
|
||||
(in the next frag), but since the > comparison
|
||||
below failed (the two were =, not >), "stretch"
|
||||
was not added to the target. Stretch was 178, so
|
||||
the offset appeared to be .-176 instead, which did
|
||||
not fit into a byte branch, so the assembler
|
||||
relaxed the branch to a word. This didn't compare
|
||||
with what happened when the same source file was
|
||||
assembled on other machines, which is how I found it.
|
||||
You might want to think about what other places have
|
||||
trouble with zero length frags... */
|
||||
|
||||
if (symbolP->sy_frag->fr_address >= was_address
|
||||
&& is_dnrange(fragP,symbolP->sy_frag)) {
|
||||
target += stretch;
|
||||
} /* */
|
||||
|
||||
} /* if there's a symbol attached */
|
||||
|
||||
start_type = this_type
|
||||
= md_relax_table + (this_state = fragP->fr_subtype);
|
||||
target = offset;
|
||||
if (symbolP)
|
||||
{
|
||||
know((S_GET_SEGMENT(symbolP) == SEG_ABSOLUTE) ||
|
||||
(S_GET_SEGMENT(symbolP) == SEG_DATA) ||
|
||||
(S_GET_SEGMENT(symbolP) == SEG_TEXT));
|
||||
know(symbolP->sy_frag);
|
||||
know(!(S_GET_SEGMENT(symbolP) == SEG_ABSOLUTE) ||
|
||||
symbolP->sy_frag==&zero_address_frag );
|
||||
target +=
|
||||
S_GET_VALUE(symbolP)
|
||||
+ symbolP->sy_frag->fr_address;
|
||||
|
||||
/* If frag has yet to be reached on this pass,
|
||||
assume it will move by STRETCH just as we did.
|
||||
If this is not so, it will be because some frag
|
||||
between grows, and that will force another pass. */
|
||||
|
||||
/* JF was just address */
|
||||
/* JF also added is_dnrange hack */
|
||||
/* There's gotta be a better/faster/etc way
|
||||
to do this. . . */
|
||||
/* gnu@cygnus.com: I changed this from > to >=
|
||||
because I ran into a zero-length frag (fr_fix=0)
|
||||
which was created when the obstack needed a new
|
||||
chunk JUST AFTER the opcode of a branch. Since
|
||||
fr_fix is zero, fr_address of this frag is the same
|
||||
as fr_address of the next frag. This
|
||||
zero-length frag was variable and jumped to .+2
|
||||
(in the next frag), but since the > comparison
|
||||
below failed (the two were =, not >), "stretch"
|
||||
was not added to the target. Stretch was 178, so
|
||||
the offset appeared to be .-176 instead, which did
|
||||
not fit into a byte branch, so the assembler
|
||||
relaxed the branch to a word. This didn't compare
|
||||
with what happened when the same source file was
|
||||
assembled on other machines, which is how I found it.
|
||||
You might want to think about what other places have
|
||||
trouble with zero length frags... */
|
||||
|
||||
if (symbolP->sy_frag->fr_address >= was_address && is_dnrange(fragP,symbolP->sy_frag))
|
||||
target += stretch;
|
||||
|
||||
}
|
||||
aim = target - address - fragP->fr_fix;
|
||||
/* The displacement is affected by the instruction size
|
||||
* for the 32k architecture. I think we ought to be able
|
||||
* to add fragP->fr_pcrel_adjust in all cases (it should be
|
||||
* zero if not used), but just in case it breaks something
|
||||
* else we'll put this inside #ifdef NS32K ... #endif
|
||||
*/
|
||||
aim = target - address - fragP->fr_fix;
|
||||
/* The displacement is affected by the instruction size
|
||||
* for the 32k architecture. I think we ought to be able
|
||||
* to add fragP->fr_pcrel_adjust in all cases (it should be
|
||||
* zero if not used), but just in case it breaks something
|
||||
* else we'll put this inside #ifdef NS32K ... #endif
|
||||
*/
|
||||
#ifdef TC_NS32K
|
||||
aim += fragP->fr_pcrel_adjust;
|
||||
aim += fragP->fr_pcrel_adjust;
|
||||
#endif /* TC_NS32K */
|
||||
|
||||
if (aim < 0)
|
||||
{
|
||||
/* Look backwards. */
|
||||
for (next_state = this_type->rlx_more; next_state; )
|
||||
{
|
||||
if (aim >= this_type->rlx_backward)
|
||||
next_state = 0;
|
||||
else
|
||||
{ /* Grow to next state. */
|
||||
this_type = md_relax_table + (this_state = next_state);
|
||||
next_state = this_type->rlx_more;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if (aim < 0) {
|
||||
/* Look backwards. */
|
||||
for (next_state = this_type->rlx_more; next_state; ) {
|
||||
if (aim >= this_type->rlx_backward) {
|
||||
next_state = 0;
|
||||
} else { /* Grow to next state. */
|
||||
this_type = md_relax_table + (this_state = next_state);
|
||||
next_state = this_type->rlx_more;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
#ifdef DONTDEF
|
||||
/* JF these next few lines of code are for the mc68020 which can't handle short
|
||||
offsets of zero in branch instructions. What a kludge! */
|
||||
if (aim==0 && this_state==(1<<2+0)) { /* FOO hard encoded from m.c */
|
||||
aim=this_type->rlx_forward+1; /* Force relaxation into word mode */
|
||||
}
|
||||
/* JF these next few lines of code are for the mc68020 which can't handle short
|
||||
offsets of zero in branch instructions. What a kludge! */
|
||||
if (aim==0 && this_state==(1<<2+0)) { /* FOO hard encoded from m.c */
|
||||
aim=this_type->rlx_forward+1; /* Force relaxation into word mode */
|
||||
}
|
||||
#endif
|
||||
/* JF end of 68020 code */
|
||||
/* Look forwards. */
|
||||
for (next_state = this_type->rlx_more; next_state; )
|
||||
{
|
||||
if (aim <= this_type->rlx_forward)
|
||||
next_state = 0;
|
||||
else
|
||||
{ /* Grow to next state. */
|
||||
this_type = md_relax_table + (this_state = next_state);
|
||||
next_state = this_type->rlx_more;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((growth = this_type->rlx_length - start_type->rlx_length) != 0)
|
||||
fragP->fr_subtype = this_state;
|
||||
}
|
||||
break;
|
||||
/* JF end of 68020 code */
|
||||
/* Look forwards. */
|
||||
for (next_state = this_type->rlx_more; next_state; ) {
|
||||
if (aim <= this_type->rlx_forward) {
|
||||
next_state = 0;
|
||||
} else { /* Grow to next state. */
|
||||
this_type = md_relax_table + (this_state = next_state);
|
||||
next_state = this_type->rlx_more;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
BAD_CASE( fragP->fr_type );
|
||||
break;
|
||||
}
|
||||
if (growth) {
|
||||
stretch += growth;
|
||||
stretched++;
|
||||
}
|
||||
} /* For each frag in the segment. */
|
||||
} while (stretched); /* Until nothing further to relax. */
|
||||
}
|
||||
if ((growth = this_type->rlx_length - start_type->rlx_length) != 0)
|
||||
fragP->fr_subtype = this_state;
|
||||
|
||||
/*
|
||||
* We now have valid fr_address'es for each frag.
|
||||
*/
|
||||
break;
|
||||
} /* case rs_machine_dependent */
|
||||
|
||||
default:
|
||||
BAD_CASE( fragP->fr_type );
|
||||
break;
|
||||
}
|
||||
if (growth) {
|
||||
stretch += growth;
|
||||
stretched++;
|
||||
}
|
||||
} /* For each frag in the segment. */
|
||||
} while (stretched); /* Until nothing further to relax. */
|
||||
} /* do_relax */
|
||||
|
||||
/*
|
||||
* We now have valid fr_address'es for each frag.
|
||||
*/
|
||||
|
||||
/*
|
||||
* All fr_address's are correct, relative to their own segment.
|
||||
* We have made all the fixS we will ever make.
|
||||
*/
|
||||
} /* relax_segment() */
|
||||
|
||||
/*
|
||||
* All fr_address's are correct, relative to their own segment.
|
||||
* We have made all the fixS we will ever make.
|
||||
*/
|
||||
} /* relax_segment() */
|
||||
|
||||
/*
|
||||
* Relax_align. Advance location counter to next address that has 'alignment'
|
||||
* lowest order bits all 0s.
|
||||
@ -895,7 +950,7 @@ register long alignment; /* Alignment (binary). */
|
||||
new_address = (address + mask) & (~ mask);
|
||||
return (new_address - address);
|
||||
} /* relax_align() */
|
||||
|
||||
|
||||
/* fixup_segment()
|
||||
|
||||
Go through all the fixS's in a segment and see which ones can be
|
||||
@ -921,7 +976,6 @@ segT this_segment_type; /* N_TYPE bits for segment. */
|
||||
register char pcrel;
|
||||
register fragS *fragP;
|
||||
register segT add_symbol_segment = SEG_ABSOLUTE;
|
||||
fixS *topP = fixP;
|
||||
|
||||
|
||||
seg_reloc_count = 0;
|
||||
@ -1093,12 +1147,16 @@ segT this_segment_type; /* N_TYPE bits for segment. */
|
||||
|
||||
#ifdef OBJ_COFF
|
||||
#ifdef TC_I960
|
||||
/* two relocs per callj under coff. */
|
||||
for (fixP = topP; fixP; fixP = fixP->fx_next) {
|
||||
if (fixP->fx_callj && fixP->fx_addsy != 0) {
|
||||
++seg_reloc_count;
|
||||
} /* if callj and not already fixed. */
|
||||
} /* for each fix */
|
||||
{
|
||||
fixS *topP = fixP;
|
||||
|
||||
/* two relocs per callj under coff. */
|
||||
for (fixP = topP; fixP; fixP = fixP->fx_next) {
|
||||
if (fixP->fx_callj && fixP->fx_addsy != 0) {
|
||||
++seg_reloc_count;
|
||||
} /* if callj and not already fixed. */
|
||||
} /* for each fix */
|
||||
}
|
||||
#endif /* TC_I960 */
|
||||
#endif /* OBJ_COFF */
|
||||
return(seg_reloc_count);
|
||||
|
Loading…
Reference in New Issue
Block a user