Polishing m68k support.

This commit is contained in:
K. Richard Pixley 1991-07-27 02:34:20 +00:00
parent 0285f1792f
commit f6e504fe91
5 changed files with 666 additions and 618 deletions

View File

@ -2,6 +2,4 @@
#include <ho-sunos.h>
extern int sprintf();
/* end of ho-sun3.h */

View File

@ -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 */

View File

@ -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");

View File

@ -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,

View File

@ -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);