mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-10-13 19:06:54 +08:00
Polishing m68k support.
This commit is contained in:
@ -2,6 +2,4 @@
|
|||||||
|
|
||||||
#include <ho-sunos.h>
|
#include <ho-sunos.h>
|
||||||
|
|
||||||
extern int sprintf();
|
|
||||||
|
|
||||||
/* end of ho-sun3.h */
|
/* 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
|
GAS is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as
|
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.
|
or (at your option) any later version.
|
||||||
|
|
||||||
GAS is distributed in the hope that it will be useful, but
|
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 */
|
/* File header macro and type definition */
|
||||||
|
|
||||||
#define H_GET_FILE_SIZE(h) (sizeof(struct exec) + \
|
#define H_GET_FILE_SIZE(h) (H_GET_HEADER_SIZE(h) \
|
||||||
H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h) + \
|
+ H_GET_TEXT_SIZE(h) \
|
||||||
H_GET_SYMBOL_TABLE_SIZE(h) + \
|
+ H_GET_DATA_SIZE(h) \
|
||||||
H_GET_TEXT_RELOCATION_SIZE(h) + \
|
+ H_GET_SYMBOL_TABLE_SIZE(h) \
|
||||||
H_GET_DATA_RELOCATION_SIZE(h) + \
|
+ H_GET_TEXT_RELOCATION_SIZE(h) \
|
||||||
(h)->string_table_size)
|
+ 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_TEXT_SIZE(h) ((h)->header.a_text)
|
||||||
#define H_GET_DATA_SIZE(h) ((h)->header.a_data)
|
#define H_GET_DATA_SIZE(h) ((h)->header.a_data)
|
||||||
#define H_GET_BSS_SIZE(h) ((h)->header.a_bss)
|
#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_MAGIC_NUMBER(h) ((h)->header.a_info)
|
||||||
#define H_GET_ENTRY_POINT(h) ((h)->header.a_entry)
|
#define H_GET_ENTRY_POINT(h) ((h)->header.a_entry)
|
||||||
#define H_GET_STRING_SIZE(h) ((h)->string_table_size)
|
#define H_GET_STRING_SIZE(h) ((h)->string_table_size)
|
||||||
|
#define H_GET_LINENO_SIZE(h) (0)
|
||||||
|
|
||||||
#ifdef EXEC_MACHINE_TYPE
|
#ifdef EXEC_MACHINE_TYPE
|
||||||
#define H_GET_MACHINE_TYPE(h) ((h)->header.a_machtype)
|
#define H_GET_MACHINE_TYPE(h) ((h)->header.a_machtype)
|
||||||
#endif /* EXEC_MACHINE_TYPE */
|
#endif /* EXEC_MACHINE_TYPE */
|
||||||
|
|
||||||
#ifdef EXEC_VERSION
|
#ifdef EXEC_VERSION
|
||||||
#define H_GET_VERSION(h) ((h)->header.a_version)
|
#define H_GET_VERSION(h) ((h)->header.a_version)
|
||||||
#endif /* EXEC_VERSION */
|
#endif /* EXEC_VERSION */
|
||||||
|
@ -927,7 +927,8 @@ md_ri_to_chars(the_bytes, ri)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* should never be called for 29k */
|
/* should never be called for 29k */
|
||||||
void md_convert_frag(fragP)
|
void md_convert_frag(headers, fragP)
|
||||||
|
object_headers *headers;
|
||||||
register fragS *fragP;
|
register fragS *fragP;
|
||||||
{
|
{
|
||||||
fprintf(stderr, "sparc_convert_frag\n");
|
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
|
GAS is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
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.
|
any later version.
|
||||||
|
|
||||||
GAS is distributed in the hope that it will be useful,
|
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. */
|
/* note that this file includes real declarations and thus can only be included by one source file per executable. */
|
||||||
#include "m68k-opcode.h"
|
#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
|
/* This array holds the chars that always start a comment. If the
|
||||||
pre-processor is disabled, these aren't very useful */
|
pre-processor is disabled, these aren't very useful */
|
||||||
@ -74,6 +83,76 @@ static struct obstack robyn;
|
|||||||
#define DBCC 5
|
#define DBCC 5
|
||||||
#define PCLEA 6
|
#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 {
|
struct m68k_exp {
|
||||||
char *e_beg;
|
char *e_beg;
|
||||||
char *e_end;
|
char *e_end;
|
||||||
@ -84,7 +163,7 @@ struct m68k_exp {
|
|||||||
/* Internal form of an operand. */
|
/* Internal form of an operand. */
|
||||||
struct m68k_op {
|
struct m68k_op {
|
||||||
char *error; /* Couldn't parse it */
|
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 */
|
unsigned long reg; /* Base register */
|
||||||
struct m68k_exp *con1;
|
struct m68k_exp *con1;
|
||||||
int ireg; /* Index register */
|
int ireg; /* Index register */
|
||||||
@ -313,73 +392,6 @@ const pseudo_typeS md_pseudo_table[] = {
|
|||||||
|
|
||||||
extern char *input_line_pointer;
|
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 FAIL 0
|
||||||
#define OK 1
|
#define OK 1
|
||||||
|
|
||||||
@ -677,6 +689,7 @@ register struct m68k_op *opP;
|
|||||||
{
|
{
|
||||||
char *strend;
|
char *strend;
|
||||||
long i;
|
long i;
|
||||||
|
char *parse_index();
|
||||||
|
|
||||||
if(*str==' ')
|
if(*str==' ')
|
||||||
str++;
|
str++;
|
||||||
@ -705,7 +718,7 @@ register struct m68k_op *opP;
|
|||||||
opP->mode=REGLST;
|
opP->mode=REGLST;
|
||||||
return get_regs(i,str,opP);
|
return get_regs(i,str,opP);
|
||||||
}
|
}
|
||||||
if((stmp=strchr(str,'@')) != '\0') {
|
if ((stmp=strchr(str,'@')) != '\0') {
|
||||||
opP->con1=add_exp(str,stmp-1);
|
opP->con1=add_exp(str,stmp-1);
|
||||||
if(stmp==strend) {
|
if(stmp==strend) {
|
||||||
opP->mode=AINDX;
|
opP->mode=AINDX;
|
||||||
@ -1018,6 +1031,7 @@ char *instring;
|
|||||||
char c;
|
char c;
|
||||||
int losing;
|
int losing;
|
||||||
int opsfound;
|
int opsfound;
|
||||||
|
char *crack_operand();
|
||||||
LITTLENUM_TYPE words[6];
|
LITTLENUM_TYPE words[6];
|
||||||
LITTLENUM_TYPE *wordp;
|
LITTLENUM_TYPE *wordp;
|
||||||
|
|
||||||
@ -1033,7 +1047,7 @@ char *instring;
|
|||||||
|
|
||||||
if (p == instring) {
|
if (p == instring) {
|
||||||
the_ins.error = "No operator";
|
the_ins.error = "No operator";
|
||||||
the_ins.opcode[0] = (short) NULL;
|
the_ins.opcode[0] = NULL;
|
||||||
/* the_ins.numo=1; */
|
/* the_ins.numo=1; */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1048,7 +1062,7 @@ char *instring;
|
|||||||
|
|
||||||
if (opcode == NULL) {
|
if (opcode == NULL) {
|
||||||
the_ins.error = "Unknown operator";
|
the_ins.error = "Unknown operator";
|
||||||
the_ins.opcode[0] = (short) NULL;
|
the_ins.opcode[0] = NULL;
|
||||||
/* the_ins.numo=1; */
|
/* the_ins.numo=1; */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1385,7 +1399,7 @@ char *instring;
|
|||||||
switch(opP->mode) {
|
switch(opP->mode) {
|
||||||
case IMMED:
|
case IMMED:
|
||||||
tmpreg=0x3c; /* 7.4 */
|
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);
|
else nextword=nextword=get_num(opP->con1,0);
|
||||||
if(isvar(opP->con1))
|
if(isvar(opP->con1))
|
||||||
add_fix(s[1],opP->con1,0);
|
add_fix(s[1],opP->con1,0);
|
||||||
@ -1434,7 +1448,7 @@ char *instring;
|
|||||||
/* We gotta put out some float */
|
/* We gotta put out some float */
|
||||||
if(seg(opP->con1)!=SEG_BIG) {
|
if(seg(opP->con1)!=SEG_BIG) {
|
||||||
int_to_gen(nextword);
|
int_to_gen(nextword);
|
||||||
gen_to_words(words,baseo,(long)outro);
|
gen_to_words(words,baseo,(long int)outro);
|
||||||
for(wordp=words;baseo--;wordp++)
|
for(wordp=words;baseo--;wordp++)
|
||||||
addword(*wordp);
|
addword(*wordp);
|
||||||
break;
|
break;
|
||||||
@ -1442,7 +1456,7 @@ char *instring;
|
|||||||
if(offs(opP->con1)>0) {
|
if(offs(opP->con1)>0) {
|
||||||
as_warn("Bignum assumed to be binary bit-pattern");
|
as_warn("Bignum assumed to be binary bit-pattern");
|
||||||
if(offs(opP->con1)>baseo) {
|
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;
|
offs(opP->con1)=baseo;
|
||||||
}
|
}
|
||||||
baseo-=offs(opP->con1);
|
baseo-=offs(opP->con1);
|
||||||
@ -1453,7 +1467,7 @@ char *instring;
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
gen_to_words(words,baseo,(long)outro);
|
gen_to_words(words,baseo,(long)outro);
|
||||||
for(wordp=words;baseo--;wordp++)
|
for (wordp=words;baseo--;wordp++)
|
||||||
addword(*wordp);
|
addword(*wordp);
|
||||||
break;
|
break;
|
||||||
case DREG:
|
case DREG:
|
||||||
@ -1664,16 +1678,21 @@ char *instring;
|
|||||||
nextword=get_num(opP->con1,80);
|
nextword=get_num(opP->con1,80);
|
||||||
switch(opP->con1->e_siz) {
|
switch(opP->con1->e_siz) {
|
||||||
default:
|
default:
|
||||||
as_bad("Unknown size for absolute reference");
|
as_warn("Unknown size for absolute reference");
|
||||||
case 0:
|
case 0:
|
||||||
if(!isvar(opP->con1) && issword(offs(opP->con1))) {
|
if(!isvar(opP->con1) && issword(offs(opP->con1))) {
|
||||||
tmpreg=0x38; /* 7.0 */
|
tmpreg=0x38; /* 7.0 */
|
||||||
addword(nextword);
|
addword(nextword);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
/* Don't generate pc relative code
|
||||||
|
on 68010 and 68000 */
|
||||||
if(isvar(opP->con1) &&
|
if(isvar(opP->con1) &&
|
||||||
!subs(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 */
|
tmpreg=0x3A; /* 7.2 */
|
||||||
add_frag(adds(opP->con1),
|
add_frag(adds(opP->con1),
|
||||||
offs(opP->con1),
|
offs(opP->con1),
|
||||||
@ -1769,46 +1788,46 @@ char *instring;
|
|||||||
case 'B':
|
case 'B':
|
||||||
tmpreg=get_num(opP->con1,80);
|
tmpreg=get_num(opP->con1,80);
|
||||||
switch(s[1]) {
|
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':
|
case 'g':
|
||||||
if(opP->con1->e_siz) { /* Deal with fixed size stuff by hand */
|
if(subs(opP->con1)) /* We can't relax it */
|
||||||
switch(opP->con1->e_siz) {
|
goto long_branch;
|
||||||
case 1:
|
|
||||||
add_fix('b',opP->con1,1);
|
/* This could either be a symbol, or an
|
||||||
break;
|
absolute address. No matter, the
|
||||||
case 2:
|
frag hacking will finger it out.
|
||||||
add_fix('w',opP->con1,1);
|
Not quite: it can't switch from
|
||||||
addword(0);
|
BRANCH to BCC68000 for the case
|
||||||
break;
|
where opnd is absolute (it needs
|
||||||
case 3:
|
to use the 68000 hack since no
|
||||||
add_fix('l',opP->con1,1);
|
conditional abs jumps). */
|
||||||
addword(0);
|
if(
|
||||||
addword(0);
|
(flagseen['m'] || (0==adds(opP->con1)))
|
||||||
break;
|
&& (the_ins.opcode[0] >= 0x6200) &&
|
||||||
default:
|
(the_ins.opcode[0] <= 0x6f00)) {
|
||||||
as_bad("Bad size for expression %d", opP->con1->e_siz);
|
add_frag(adds(opP->con1),offs(opP->con1),TAB(BCC68000,SZ_UNDEF));
|
||||||
}
|
|
||||||
} 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));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
/* JF: This is the WRONG thing to do
|
add_frag(adds(opP->con1),offs(opP->con1),TAB(BRANCH,SZ_UNDEF));
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'w':
|
case 'w':
|
||||||
@ -1827,24 +1846,18 @@ char *instring;
|
|||||||
}
|
}
|
||||||
addword(0);
|
addword(0);
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'C': /* Fixed size LONG coproc branches */
|
||||||
if(opP->con1->e_siz) {
|
the_ins.opcode[the_ins.numo-1]|=0x40;
|
||||||
switch(opP->con1->e_siz) {
|
/* Offset the displacement to be relative to byte disp location */
|
||||||
case 2:
|
/* Coproc branches don't have a byte disp option, but they are
|
||||||
add_fix('w',opP->con1,1)
|
compatible with the ordinary branches, which do... */
|
||||||
addword(0);
|
opP->con1->e_exp.X_add_number+=4;
|
||||||
break;
|
add_fix('l',opP->con1,1);
|
||||||
case 3:
|
addword(0);
|
||||||
the_ins.opcode[the_ins.numo-1]|=0x40;
|
addword(0);
|
||||||
add_fix('l',opP->con1,1);
|
break;
|
||||||
addword(0);
|
case 'c': /* Var size Coprocesssor branches */
|
||||||
addword(0);
|
if(subs(opP->con1)) {
|
||||||
break;
|
|
||||||
default:
|
|
||||||
as_bad("Bad size for offset, must be word or long");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if(subs(opP->con1)) {
|
|
||||||
add_fix('l',opP->con1,1);
|
add_fix('l',opP->con1,1);
|
||||||
add_frag((symbolS *)0,(long)0,TAB(FBRANCH,LONG));
|
add_frag((symbolS *)0,(long)0,TAB(FBRANCH,LONG));
|
||||||
} else if(adds(opP->con1)) {
|
} else if(adds(opP->con1)) {
|
||||||
@ -1884,7 +1897,7 @@ char *instring;
|
|||||||
}
|
}
|
||||||
tmpreg=get_num(opP->con1,80);
|
tmpreg=get_num(opP->con1,80);
|
||||||
if(!issword(tmpreg)) {
|
if(!issword(tmpreg)) {
|
||||||
as_bad("Expression out of range, using 0");
|
as_warn("Expression out of range, using 0");
|
||||||
tmpreg=0;
|
tmpreg=0;
|
||||||
}
|
}
|
||||||
addword(tmpreg);
|
addword(tmpreg);
|
||||||
@ -2357,7 +2370,7 @@ char *s;
|
|||||||
return 0;
|
return 0;
|
||||||
if(*s!=':') return 1;
|
if(*s!=':') return 1;
|
||||||
/* This kludge here is for the division cmd, which is a kludge */
|
/* 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;
|
return 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -2552,7 +2565,7 @@ obstack_alloc(&robyn,sizeof(struct m68_incant));
|
|||||||
retval = hash_insert (op_hash, ins->name,(char *)hack);
|
retval = hash_insert (op_hash, ins->name,(char *)hack);
|
||||||
/* Didn't his mommy tell him about null pointers? */
|
/* Didn't his mommy tell him about null pointers? */
|
||||||
if(retval && *retval)
|
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++)
|
for (i = 0; i < sizeof(mklower_table) ; i++)
|
||||||
@ -2608,6 +2621,7 @@ int *sizeP;
|
|||||||
LITTLENUM_TYPE words[MAX_LITTLENUMS];
|
LITTLENUM_TYPE words[MAX_LITTLENUMS];
|
||||||
LITTLENUM_TYPE *wordP;
|
LITTLENUM_TYPE *wordP;
|
||||||
char *t;
|
char *t;
|
||||||
|
char *atof_ieee();
|
||||||
|
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case 'f':
|
case 'f':
|
||||||
@ -2714,21 +2728,31 @@ md_apply_fix(fixP, val)
|
|||||||
MAGIC here. ..
|
MAGIC here. ..
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
md_convert_frag(fragP)
|
md_convert_frag(headers, fragP)
|
||||||
|
object_headers *headers;
|
||||||
register fragS *fragP;
|
register fragS *fragP;
|
||||||
{
|
{
|
||||||
long disp;
|
long disp;
|
||||||
long ext;
|
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. */
|
/* Address in object code of the displacement. */
|
||||||
register int object_address = fragP -> fr_fix + fragP -> fr_address;
|
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. */
|
/* 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) {
|
switch(fragP->fr_subtype) {
|
||||||
case TAB(BCC68000,BYTE):
|
case TAB(BCC68000,BYTE):
|
||||||
@ -2753,7 +2777,7 @@ register fragS *fragP;
|
|||||||
if(flagseen['m']) {
|
if(flagseen['m']) {
|
||||||
if(fragP->fr_opcode[0]==0x61) {
|
if(fragP->fr_opcode[0]==0x61) {
|
||||||
fragP->fr_opcode[0]= 0x4E;
|
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);
|
subseg_change(SEG_TEXT, 0);
|
||||||
|
|
||||||
fix_new(fragP,
|
fix_new(fragP,
|
||||||
@ -2833,21 +2857,20 @@ register fragS *fragP;
|
|||||||
ext=2;
|
ext=2;
|
||||||
break;
|
break;
|
||||||
case TAB(PCREL,LONG):
|
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
|
/* The thing to do here is force it to ABSOLUTE LONG, since
|
||||||
PCREL is really trying to shorten an ABSOLUTE address anyway */
|
PCREL is really trying to shorten an ABSOLUTE address anyway */
|
||||||
|
/* JF FOO This code has not been tested */
|
||||||
subseg_change(SEG_TEXT,0);
|
subseg_change(SEG_TEXT,0);
|
||||||
fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, fragP->fr_offset, 0,
|
fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, fragP->fr_offset, 0, NO_RELOC);
|
||||||
NO_RELOC);
|
|
||||||
if((fragP->fr_opcode[1] & 0x3F) != 0x3A)
|
if((fragP->fr_opcode[1] & 0x3F) != 0x3A)
|
||||||
as_bad("Internal error (long PC-relative operand) for insn 0x%04lx at 0x%lx",
|
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[0],fragP->fr_address);
|
||||||
fragP->fr_opcode[1]&= ~0x3F;
|
fragP->fr_opcode[1]&= ~0x3F;
|
||||||
fragP->fr_opcode[1]|=0x39; /* Mode 7.1 */
|
fragP->fr_opcode[1]|=0x39; /* Mode 7.1 */
|
||||||
fragP->fr_fix+=4;
|
fragP->fr_fix+=4;
|
||||||
|
/* md_number_to_chars(buffer_address,
|
||||||
|
(long)(fragP->fr_symbol->sy_value + fragP->fr_offset),
|
||||||
|
4); */
|
||||||
ext=0;
|
ext=0;
|
||||||
break;
|
break;
|
||||||
case TAB(PCLEA,SHORT):
|
case TAB(PCLEA,SHORT):
|
||||||
@ -2869,12 +2892,20 @@ register fragS *fragP;
|
|||||||
ext=4;
|
ext=4;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
} /* switch on subtype */
|
||||||
if(ext) {
|
|
||||||
md_number_to_chars(buffer_address,(long)disp,(int)ext);
|
if (ext) {
|
||||||
fragP->fr_fix+=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
|
/* Force truly undefined symbols to their maximum size, and generally set up
|
||||||
the frag list to be relaxed
|
the frag list to be relaxed
|
||||||
@ -2890,105 +2921,10 @@ segT segment;
|
|||||||
|
|
||||||
/* handle SZ_UNDEF first, it can be changed to BYTE or SHORT */
|
/* handle SZ_UNDEF first, it can be changed to BYTE or SHORT */
|
||||||
switch(fragP->fr_subtype) {
|
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):
|
case TAB(BCC68000,SZ_UNDEF): {
|
||||||
if(S_GET_SEGMENT(fragP->fr_symbol) == segment
|
if((fragP->fr_symbol != NULL)
|
||||||
|| flagseen['l']) {
|
&& S_GET_SEGMENT(fragP->fr_symbol) == segment) {
|
||||||
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) {
|
|
||||||
fragP->fr_subtype=TAB(BCC68000,BYTE);
|
fragP->fr_subtype=TAB(BCC68000,BYTE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3003,8 +2939,7 @@ segT segment;
|
|||||||
fragP->fr_fix += 2; /* account for jmp instruction */
|
fragP->fr_fix += 2; /* account for jmp instruction */
|
||||||
subseg_change(SEG_TEXT,0);
|
subseg_change(SEG_TEXT,0);
|
||||||
fix_new(fragP, fragP->fr_fix, 2, fragP->fr_symbol, 0,
|
fix_new(fragP, fragP->fr_fix, 2, fragP->fr_symbol, 0,
|
||||||
fragP->fr_offset,0,
|
fragP->fr_offset, 0, NO_RELOC);
|
||||||
NO_RELOC);
|
|
||||||
fragP->fr_fix += 2;
|
fragP->fr_fix += 2;
|
||||||
} else {
|
} else {
|
||||||
fragP->fr_opcode[1] = 0x06; /* branch offset = 6 */
|
fragP->fr_opcode[1] = 0x06; /* branch offset = 6 */
|
||||||
@ -3014,15 +2949,15 @@ segT segment;
|
|||||||
fragP->fr_fix += 2; /* account for jmp instruction */
|
fragP->fr_fix += 2; /* account for jmp instruction */
|
||||||
subseg_change(SEG_TEXT,0);
|
subseg_change(SEG_TEXT,0);
|
||||||
fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0,
|
fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0,
|
||||||
fragP->fr_offset,0,
|
fragP->fr_offset, 0, NO_RELOC);
|
||||||
NO_RELOC);
|
|
||||||
fragP->fr_fix += 4;
|
fragP->fr_fix += 4;
|
||||||
}
|
}
|
||||||
frag_wane(fragP);
|
frag_wane(fragP);
|
||||||
break;
|
break;
|
||||||
|
} /* case TAB(BCC68000,SZ_UNDEF) */
|
||||||
|
|
||||||
case TAB(DBCC,SZ_UNDEF):
|
case TAB(DBCC,SZ_UNDEF): {
|
||||||
if(S_GET_SEGMENT(fragP->fr_symbol) == segment) {
|
if (fragP->fr_symbol != NULL && S_GET_SEGMENT(fragP->fr_symbol) == segment) {
|
||||||
fragP->fr_subtype=TAB(DBCC,SHORT);
|
fragP->fr_subtype=TAB(DBCC,SHORT);
|
||||||
fragP->fr_var+=2;
|
fragP->fr_var+=2;
|
||||||
break;
|
break;
|
||||||
@ -3032,7 +2967,8 @@ segT segment;
|
|||||||
/* JF: these used to be fr_opcode[2-4], which is wrong. */
|
/* JF: these used to be fr_opcode[2-4], which is wrong. */
|
||||||
buffer_address[0] = 0x00; /* branch offset = 4 */
|
buffer_address[0] = 0x00; /* branch offset = 4 */
|
||||||
buffer_address[1] = 0x04;
|
buffer_address[1] = 0x04;
|
||||||
buffer_address[2] = 0x60; /* put in bra pc + ... */
|
buffer_address[2] = 0x60; /* put in bra pc + ... */
|
||||||
|
|
||||||
if(flagseen['l']) {
|
if(flagseen['l']) {
|
||||||
/* JF: these were fr_opcode[5-7] */
|
/* JF: these were fr_opcode[5-7] */
|
||||||
buffer_address[3] = 0x04; /* plus 4 */
|
buffer_address[3] = 0x04; /* plus 4 */
|
||||||
@ -3041,9 +2977,8 @@ segT segment;
|
|||||||
fragP->fr_fix += 6; /* account for bra/jmp instruction */
|
fragP->fr_fix += 6; /* account for bra/jmp instruction */
|
||||||
subseg_change(SEG_TEXT,0);
|
subseg_change(SEG_TEXT,0);
|
||||||
fix_new(fragP, fragP->fr_fix, 2, fragP->fr_symbol, 0,
|
fix_new(fragP, fragP->fr_fix, 2, fragP->fr_symbol, 0,
|
||||||
fragP->fr_offset,0,
|
fragP->fr_offset, 0, NO_RELOC);
|
||||||
NO_RELOC);
|
fragP->fr_fix += 2;
|
||||||
fragP->fr_fix+=2;
|
|
||||||
} else {
|
} else {
|
||||||
/* JF: these were fr_opcode[5-7] */
|
/* JF: these were fr_opcode[5-7] */
|
||||||
buffer_address[3] = 0x06; /* Plus 6 */
|
buffer_address[3] = 0x06; /* Plus 6 */
|
||||||
@ -3052,15 +2987,53 @@ segT segment;
|
|||||||
fragP->fr_fix += 6; /* account for bra/jmp instruction */
|
fragP->fr_fix += 6; /* account for bra/jmp instruction */
|
||||||
subseg_change(SEG_TEXT,0);
|
subseg_change(SEG_TEXT,0);
|
||||||
fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0,
|
fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0,
|
||||||
fragP->fr_offset,0,
|
fragP->fr_offset, 0, NO_RELOC);
|
||||||
NO_RELOC);
|
|
||||||
fragP->fr_fix += 4;
|
fragP->fr_fix += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
frag_wane(fragP);
|
frag_wane(fragP);
|
||||||
break;
|
break;
|
||||||
|
} /* case TAB(DBCC,SZ_UNDEF) */
|
||||||
|
|
||||||
case TAB(PCLEA,SZ_UNDEF):
|
case TAB(BRANCH,SZ_UNDEF): {
|
||||||
if((S_GET_SEGMENT(fragP->fr_symbol))==segment || flagseen['l']) {
|
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_subtype=TAB(PCLEA,SHORT);
|
||||||
fragP->fr_var+=2;
|
fragP->fr_var+=2;
|
||||||
} else {
|
} else {
|
||||||
@ -3068,6 +3041,18 @@ segT segment;
|
|||||||
fragP->fr_var+=6;
|
fragP->fr_var+=6;
|
||||||
}
|
}
|
||||||
break;
|
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:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -3079,7 +3064,7 @@ segT segment;
|
|||||||
case TAB(BRANCH,BYTE):
|
case TAB(BRANCH,BYTE):
|
||||||
/* We can't do a short jump to the next instruction,
|
/* We can't do a short jump to the next instruction,
|
||||||
so we force word mode. */
|
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_symbol->sy_frag==fragP->fr_next) {
|
||||||
fragP->fr_subtype=TAB(TABTYPE(fragP->fr_subtype),SHORT);
|
fragP->fr_subtype=TAB(TABTYPE(fragP->fr_subtype),SHORT);
|
||||||
fragP->fr_var+=2;
|
fragP->fr_var+=2;
|
||||||
@ -3148,7 +3133,7 @@ symbolS *to_symbol;
|
|||||||
{
|
{
|
||||||
long offset;
|
long offset;
|
||||||
|
|
||||||
if(flagseen['m']) {
|
if (flagseen['m']) {
|
||||||
offset=to_addr-S_GET_VALUE(to_symbol);
|
offset=to_addr-S_GET_VALUE(to_symbol);
|
||||||
md_number_to_chars(ptr ,(long)0x4EF9,2);
|
md_number_to_chars(ptr ,(long)0x4EF9,2);
|
||||||
md_number_to_chars(ptr+2,(long)offset,4);
|
md_number_to_chars(ptr+2,(long)offset,4);
|
||||||
@ -3207,7 +3192,7 @@ int ok;
|
|||||||
adds(exp)=0;
|
adds(exp)=0;
|
||||||
subs(exp)=0;
|
subs(exp)=0;
|
||||||
offs(exp)= (ok==10) ? 1 : 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3229,7 +3214,7 @@ int ok;
|
|||||||
exp->e_siz=3;
|
exp->e_siz=3;
|
||||||
break;
|
break;
|
||||||
default:
|
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;
|
exp->e_end-=2;
|
||||||
}
|
}
|
||||||
@ -3243,7 +3228,7 @@ int ok;
|
|||||||
adds(exp)=0;
|
adds(exp)=0;
|
||||||
subs(exp)=0;
|
subs(exp)=0;
|
||||||
offs(exp)= (ok==10) ? 1 : 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;
|
break;
|
||||||
|
|
||||||
case SEG_ABSENT:
|
case SEG_ABSENT:
|
||||||
@ -3253,7 +3238,7 @@ int ok;
|
|||||||
subs(exp)=0;
|
subs(exp)=0;
|
||||||
offs(exp)=0;
|
offs(exp)=0;
|
||||||
if(ok==10) {
|
if(ok==10) {
|
||||||
as_bad("expression out of range: defaulting to 1");
|
as_warn("expression out of range: defaulting to 1");
|
||||||
offs(exp)=1;
|
offs(exp)=1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -3261,7 +3246,7 @@ int ok;
|
|||||||
switch(ok) {
|
switch(ok) {
|
||||||
case 10:
|
case 10:
|
||||||
if(offs(exp)<1 || offs(exp)>8) {
|
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;
|
offs(exp)=1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -3292,7 +3277,7 @@ int ok;
|
|||||||
case 70:
|
case 70:
|
||||||
if(offs(exp)<0 || offs(exp)>4095) {
|
if(offs(exp)<0 || offs(exp)>4095) {
|
||||||
outrange:
|
outrange:
|
||||||
as_bad("expression out of range: defaulting to 0");
|
as_warn("expression out of range: defaulting to 0");
|
||||||
offs(exp)=0;
|
offs(exp)=0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -3310,7 +3295,7 @@ int ok;
|
|||||||
adds(exp)=0;
|
adds(exp)=0;
|
||||||
subs(exp)=0;
|
subs(exp)=0;
|
||||||
offs(exp)= (ok==10) ? 1 : 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;
|
break;
|
||||||
case SEG_BIG:
|
case SEG_BIG:
|
||||||
@ -3327,7 +3312,7 @@ int ok;
|
|||||||
adds(exp)=0;
|
adds(exp)=0;
|
||||||
subs(exp)=0;
|
subs(exp)=0;
|
||||||
offs(exp)= (ok==10) ? 1 : 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;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -3341,11 +3326,11 @@ int ok;
|
|||||||
switch(exp->e_siz) {
|
switch(exp->e_siz) {
|
||||||
case 1:
|
case 1:
|
||||||
if(!isbyte(offs(exp)))
|
if(!isbyte(offs(exp)))
|
||||||
as_bad("expression doesn't fit in BYTE");
|
as_warn("expression doesn't fit in BYTE");
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if(!isword(offs(exp)))
|
if(!isword(offs(exp)))
|
||||||
as_bad("expression doesn't fit in WORD");
|
as_warn("expression doesn't fit in WORD");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3354,6 +3339,7 @@ int ok;
|
|||||||
} /* get_num() */
|
} /* get_num() */
|
||||||
|
|
||||||
/* These are the back-ends for the various machine dependent pseudo-ops. */
|
/* 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() {
|
static void s_data1() {
|
||||||
subseg_new(SEG_DATA,1);
|
subseg_new(SEG_DATA,1);
|
||||||
@ -3396,8 +3382,8 @@ int *cntP;
|
|||||||
char ***vecP;
|
char ***vecP;
|
||||||
{
|
{
|
||||||
switch(**argP) {
|
switch(**argP) {
|
||||||
case 'l': /* -l means keep externals to 2 byte branch offsets
|
case 'l': /* -l means keep external to 2 bit offset
|
||||||
rather than 4 byte branch offsets */
|
rather than 16 bit one */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'm':
|
case 'm':
|
||||||
@ -3409,7 +3395,7 @@ char ***vecP;
|
|||||||
flagseen['m']=2;
|
flagseen['m']=2;
|
||||||
else if(!strcmp(*argP,"68010")) {
|
else if(!strcmp(*argP,"68010")) {
|
||||||
#ifdef TE_SUN
|
#ifdef TE_SUN
|
||||||
magic_number_for_object_file = 1<<16|OMAGIC;
|
omagic= 1<<16|OMAGIC;
|
||||||
#endif
|
#endif
|
||||||
flagseen['m']=1;
|
flagseen['m']=1;
|
||||||
} else if(!strcmp(*argP,"68020"))
|
} 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
|
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
|
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.
|
any later version.
|
||||||
|
|
||||||
GDB and GAS are distributed in the hope that it will be useful,
|
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
|
GAS is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
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.
|
any later version.
|
||||||
|
|
||||||
GAS is distributed in the hope that it will be useful,
|
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_offset = offset;
|
||||||
fixP->fx_pcrel = pcrel;
|
fixP->fx_pcrel = pcrel;
|
||||||
fixP->fx_r_type = r_type;
|
fixP->fx_r_type = r_type;
|
||||||
fixP->fx_next = NULL;
|
|
||||||
|
|
||||||
/* JF these 'cuz of the NS32K stuff */
|
/* JF these 'cuz of the NS32K stuff */
|
||||||
fixP->fx_im_disp = 0;
|
fixP->fx_im_disp = 0;
|
||||||
@ -123,15 +122,32 @@ enum reloc_type r_type; /* Relocation type */
|
|||||||
fixP->fx_bsr = 0;
|
fixP->fx_bsr = 0;
|
||||||
fixP->fx_bit_fixP = 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)
|
if (*seg_fix_tailP)
|
||||||
(*seg_fix_tailP)->fx_next = fixP;
|
(*seg_fix_tailP)->fx_next = fixP;
|
||||||
else
|
else
|
||||||
*seg_fix_rootP = fixP;
|
*seg_fix_rootP = fixP;
|
||||||
*seg_fix_tailP = fixP;
|
*seg_fix_tailP = fixP;
|
||||||
|
|
||||||
|
#endif /* REVERSE_SORT_RELOCS */
|
||||||
|
|
||||||
fixP->fx_callj = 0;
|
fixP->fx_callj = 0;
|
||||||
return fixP;
|
return fixP;
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_object_file() {
|
void write_object_file() {
|
||||||
register struct frchain * frchainP; /* Track along all frchains. */
|
register struct frchain * frchainP; /* Track along all frchains. */
|
||||||
register fragS * fragP; /* Track along all frags. */
|
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 ); */
|
/* know( frags . obstack_c_base == frags . obstack_c_next_free ); */
|
||||||
/* Above shows we haven't left a half-completed object on obstack. */
|
/* Above shows we haven't left a half-completed object on obstack. */
|
||||||
} /* walk the frag chain */
|
} /* walk the frag chain */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* From now on, we don't care about sub-segments.
|
* From now on, we don't care about sub-segments.
|
||||||
* Build one frag chain for each segment. Linked thru fr_next.
|
* 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);
|
know(text_last_frag->fr_type == rs_fill && text_last_frag->fr_offset == 0);
|
||||||
H_SET_TEXT_SIZE(&headers,text_last_frag->fr_address);
|
H_SET_TEXT_SIZE(&headers, text_last_frag->fr_address);
|
||||||
text_last_frag->fr_address=H_GET_TEXT_SIZE(&headers);
|
text_last_frag->fr_address = H_GET_TEXT_SIZE(&headers);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Join the 2 segments into 1 huge segment.
|
* Join the 2 segments into 1 huge segment.
|
||||||
@ -251,20 +267,20 @@ void write_object_file() {
|
|||||||
* Determine a_data [length of data segment].
|
* Determine a_data [length of data segment].
|
||||||
*/
|
*/
|
||||||
if (data_frag_root) {
|
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);
|
H_SET_DATA_SIZE(&headers, data_last_frag->fr_address);
|
||||||
data_last_frag->fr_address = H_GET_DATA_SIZE(&headers);
|
data_last_frag->fr_address = H_GET_DATA_SIZE(&headers);
|
||||||
slide = H_GET_TEXT_SIZE(&headers); /* & in file of the data segment. */
|
slide = H_GET_TEXT_SIZE(&headers); /* & in file of the data segment. */
|
||||||
|
|
||||||
for (fragP = data_frag_root;
|
for (fragP = data_frag_root; fragP; fragP = fragP->fr_next) {
|
||||||
fragP;
|
fragP->fr_address += slide;
|
||||||
fragP = fragP->fr_next)
|
} /* for each data frag */
|
||||||
{
|
|
||||||
fragP->fr_address += slide;
|
know(text_last_frag != 0);
|
||||||
}
|
|
||||||
know( text_last_frag );
|
|
||||||
text_last_frag->fr_next = data_frag_root;
|
text_last_frag->fr_next = data_frag_root;
|
||||||
} else {
|
} else {
|
||||||
H_SET_DATA_SIZE(&headers,0);
|
H_SET_DATA_SIZE(&headers,0);
|
||||||
@ -321,25 +337,25 @@ void write_object_file() {
|
|||||||
case rs_align:
|
case rs_align:
|
||||||
case rs_org:
|
case rs_org:
|
||||||
fragP->fr_type = rs_fill;
|
fragP->fr_type = rs_fill;
|
||||||
know( fragP->fr_var == 1 );
|
know(fragP->fr_var == 1);
|
||||||
know( fragP->fr_next );
|
know(fragP->fr_next != NULL);
|
||||||
fragP->fr_offset
|
|
||||||
= fragP->fr_next->fr_address
|
fragP->fr_offset = (fragP->fr_next->fr_address
|
||||||
- fragP->fr_address
|
- fragP->fr_address
|
||||||
- fragP->fr_fix;
|
- fragP->fr_fix);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case rs_fill:
|
case rs_fill:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case rs_machine_dependent:
|
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".
|
* After md_convert_frag, we make the frag into a ".space 0".
|
||||||
* Md_convert_frag() should set up any fixSs and constants
|
* Md_convert_frag() should set up any fixSs and constants
|
||||||
* required.
|
* required.
|
||||||
*/
|
*/
|
||||||
frag_wane (fragP);
|
frag_wane(fragP);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifndef WORKING_DOT_WORD
|
#ifndef WORKING_DOT_WORD
|
||||||
@ -463,13 +479,13 @@ void write_object_file() {
|
|||||||
|
|
||||||
/* FIXME move this stuff into the pre-write-hook */
|
/* FIXME move this stuff into the pre-write-hook */
|
||||||
H_SET_MAGIC_NUMBER(&headers, magic_number_for_object_file);
|
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
|
#ifdef EXEC_MACHINE_TYPE
|
||||||
H_SET_MACHINE_TYPE(&headers,EXEC_MACHINE_TYPE);
|
H_SET_MACHINE_TYPE(&headers, EXEC_MACHINE_TYPE);
|
||||||
#endif
|
#endif
|
||||||
#ifdef EXEC_VERSION
|
#ifdef EXEC_VERSION
|
||||||
H_SET_VERSION(&headers,EXEC_VERSION);
|
H_SET_VERSION(&headers, EXEC_VERSION);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
obj_pre_write_hook(&headers); /* extra coff stuff */
|
obj_pre_write_hook(&headers); /* extra coff stuff */
|
||||||
@ -493,29 +509,42 @@ void write_object_file() {
|
|||||||
output_file_create(out_file_name);
|
output_file_create(out_file_name);
|
||||||
|
|
||||||
obj_header_append(&next_object_file_charP, &headers);
|
obj_header_append(&next_object_file_charP, &headers);
|
||||||
|
know((next_object_file_charP - the_object_file) == H_GET_HEADER_SIZE(&headers));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Emit code.
|
* Emit code.
|
||||||
*/
|
*/
|
||||||
for (fragP = text_frag_root; fragP; fragP = fragP->fr_next) {
|
for (fragP = text_frag_root; fragP; fragP = fragP->fr_next) {
|
||||||
register long count;
|
register long count;
|
||||||
register char * fill_literal;
|
register char *fill_literal;
|
||||||
register long fill_size;
|
register long fill_size;
|
||||||
|
|
||||||
know( fragP->fr_type == rs_fill );
|
know(fragP->fr_type == rs_fill);
|
||||||
append (& next_object_file_charP, fragP->fr_literal, (unsigned long)fragP->fr_fix);
|
append(&next_object_file_charP, fragP->fr_literal, (unsigned long) fragP->fr_fix);
|
||||||
fill_literal= fragP->fr_literal + fragP->fr_fix;
|
fill_literal = fragP->fr_literal + fragP->fr_fix;
|
||||||
fill_size = fragP->fr_var;
|
fill_size = fragP->fr_var;
|
||||||
know( fragP->fr_offset >= 0 );
|
know(fragP->fr_offset >= 0);
|
||||||
for (count = fragP->fr_offset; count; count --)
|
|
||||||
append (& next_object_file_charP, fill_literal, (unsigned long)fill_size);
|
for (count = fragP->fr_offset; count; count--) {
|
||||||
|
append(&next_object_file_charP, fill_literal, (unsigned long) fill_size);
|
||||||
|
} /* for each */
|
||||||
|
|
||||||
} /* for each code frag. */
|
} /* 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.
|
* Emit relocations.
|
||||||
*/
|
*/
|
||||||
obj_emit_relocations(&next_object_file_charP, text_fix_root, (relax_addressT)0);
|
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
|
#ifdef TC_I960
|
||||||
/* Make addresses in data relocation directives relative to beginning of
|
/* Make addresses in data relocation directives relative to beginning of
|
||||||
* first data fragment, not end of last text fragment: alignment of the
|
* 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);
|
obj_emit_relocations(&next_object_file_charP, data_fix_root, text_last_frag->fr_address);
|
||||||
#endif /* TC_I960 */
|
#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.
|
* Emit line number entries.
|
||||||
*/
|
*/
|
||||||
OBJ_EMIT_LINENO(&next_object_file_charP, lineno_rootP, the_object_file);
|
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.
|
* Emit symbols.
|
||||||
*/
|
*/
|
||||||
obj_emit_symbols(&next_object_file_charP, symbol_rootP);
|
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.
|
* Emit strings.
|
||||||
*/
|
*/
|
||||||
@ -544,6 +595,16 @@ void write_object_file() {
|
|||||||
obj_emit_strings(&next_object_file_charP);
|
obj_emit_strings(&next_object_file_charP);
|
||||||
} /* only if we have a string table */
|
} /* 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);
|
know(next_object_file_charP == the_object_file + object_file_size);
|
||||||
/* Write the data to the file */
|
/* Write the data to the file */
|
||||||
output_file_append(the_object_file,object_file_size,out_file_name);
|
output_file_append(the_object_file,object_file_size,out_file_name);
|
||||||
@ -581,303 +642,297 @@ void write_object_file() {
|
|||||||
#ifndef VMS
|
#ifndef VMS
|
||||||
static
|
static
|
||||||
#endif /* not VMS */
|
#endif /* not VMS */
|
||||||
void relax_segment(segment_frag_root, segment_type)
|
void relax_segment(segment_frag_root, segment)
|
||||||
struct frag * segment_frag_root;
|
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 struct frag * fragP;
|
||||||
register relax_addressT address;
|
register relax_addressT address;
|
||||||
/* register relax_addressT old_address; JF unused */
|
/* register relax_addressT old_address; JF unused */
|
||||||
/* register relax_addressT new_address; JF unused */
|
/* register relax_addressT new_address; JF unused */
|
||||||
|
|
||||||
know( segment_type == SEG_DATA || segment_type == SEG_TEXT );
|
know( segment == SEG_DATA || segment == SEG_TEXT );
|
||||||
|
|
||||||
/* In case md_estimate_size_before_relax() wants to make fixSs. */
|
/* In case md_estimate_size_before_relax() wants to make fixSs. */
|
||||||
subseg_change(segment_type, 0);
|
subseg_change(segment, 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For each frag in segment: count and store (a 1st guess of) fr_address.
|
* For each frag in segment: count and store (a 1st guess of) fr_address.
|
||||||
*/
|
*/
|
||||||
address = 0;
|
address = 0;
|
||||||
for ( fragP = segment_frag_root; fragP; fragP = fragP->fr_next )
|
for (fragP = segment_frag_root; fragP; fragP = fragP->fr_next) {
|
||||||
{
|
fragP->fr_address = address;
|
||||||
fragP->fr_address = address;
|
address += fragP->fr_fix;
|
||||||
address += fragP->fr_fix;
|
|
||||||
switch (fragP->fr_type)
|
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:
|
register long stretch; /* May be any size, 0 or negative. */
|
||||||
address += fragP->fr_offset * fragP->fr_var;
|
/* Cumulative number of addresses we have */
|
||||||
break;
|
/* relaxed this pass. */
|
||||||
|
/* We may have relaxed more than one address. */
|
||||||
case rs_align:
|
register long stretched; /* Have we stretched on this pass? */
|
||||||
address += relax_align(address, fragP->fr_offset);
|
/* This is 'cuz stretch may be zero, when,
|
||||||
break;
|
in fact some piece of code grew, and
|
||||||
|
another shrank. If a branch instruction
|
||||||
case rs_org:
|
doesn't fit anymore, we could be scrod */
|
||||||
/*
|
|
||||||
* Assume .org is nugatory. It will grow with 1st relax.
|
do {
|
||||||
*/
|
stretch = stretched = 0;
|
||||||
break;
|
for (fragP = segment_frag_root; fragP; fragP = fragP->fr_next) {
|
||||||
|
register long growth = 0;
|
||||||
case rs_machine_dependent:
|
register unsigned long was_address;
|
||||||
address += md_estimate_size_before_relax(fragP, segment_type);
|
/* register long var; */
|
||||||
break;
|
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
|
#ifndef WORKING_DOT_WORD
|
||||||
/* Broken words don't concern us yet */
|
/* JF: This is RMS's idea. I do *NOT* want to be blamed
|
||||||
case rs_broken_word:
|
for it I do not want to write it. I do not want to have
|
||||||
break;
|
anything to do with it. This is not the proper way to
|
||||||
#endif
|
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:
|
offset= lie->add->sy_frag->fr_address+ S_GET_VALUE(lie->add) + lie->addnum -
|
||||||
BAD_CASE( fragP->fr_type );
|
(lie->sub->sy_frag->fr_address+ S_GET_VALUE(lie->sub));
|
||||||
break;
|
if (offset<=-32768 || offset>=32767) {
|
||||||
} /* switch(fr_type) */
|
if (flagseen['k'])
|
||||||
} /* for each frag in the segment */
|
as_warn(".word %s-%s+%ld didn't fit",
|
||||||
|
S_GET_NAME(lie->add),
|
||||||
/*
|
S_GET_NAME(lie->sub),
|
||||||
* Do relax().
|
lie->addnum);
|
||||||
*/
|
lie->added=1;
|
||||||
{
|
if (fragP->fr_subtype==0) {
|
||||||
register long stretch; /* May be any size, 0 or negative. */
|
fragP->fr_subtype++;
|
||||||
/* Cumulative number of addresses we have */
|
growth+=md_short_jump_size;
|
||||||
/* relaxed this pass. */
|
}
|
||||||
/* We may have relaxed more than one address. */
|
for (untruth=lie->next_broken_word;untruth && untruth->dispfrag==lie->dispfrag;untruth=untruth->next_broken_word)
|
||||||
register long stretched; /* Have we stretched on this pass? */
|
if ((untruth->add->sy_frag == lie->add->sy_frag)
|
||||||
/* This is 'cuz stretch may be zero, when,
|
&& S_GET_VALUE(untruth->add) == S_GET_VALUE(lie->add)) {
|
||||||
in fact some piece of code grew, and
|
untruth->added=2;
|
||||||
another shrank. If a branch instruction
|
untruth->use_jump=lie;
|
||||||
doesn't fit anymore, we could be scrod */
|
}
|
||||||
|
growth+=md_long_jump_size;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
growth+=md_long_jump_size;
|
|
||||||
}
|
break;
|
||||||
}
|
} /* case rs_broken_word */
|
||||||
}
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
case rs_align:
|
case rs_align:
|
||||||
growth = relax_align ((relax_addressT)(address + fragP->fr_fix), offset)
|
growth = relax_align((relax_addressT) (address + fragP->fr_fix), offset)
|
||||||
- relax_align ((relax_addressT)(was_address + fragP->fr_fix), offset);
|
- relax_align((relax_addressT) (was_address + fragP->fr_fix), offset);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case rs_org:
|
||||||
|
target = offset;
|
||||||
|
|
||||||
case rs_org:
|
if (symbolP) {
|
||||||
target = offset;
|
know((S_GET_SEGMENT(symbolP) == SEG_ABSOLUTE)
|
||||||
if (symbolP)
|
|| (S_GET_SEGMENT(symbolP) == SEG_DATA)
|
||||||
{
|
|| (S_GET_SEGMENT(symbolP) == SEG_TEXT));
|
||||||
know((S_GET_SEGMENT(symbolP) == SEG_ABSOLUTE) ||
|
know(symbolP->sy_frag);
|
||||||
(S_GET_SEGMENT(symbolP) == SEG_DATA) ||
|
know(!(S_GET_SEGMENT(symbolP) == SEG_ABSOLUTE)
|
||||||
(S_GET_SEGMENT(symbolP) == SEG_TEXT));
|
|| (symbolP->sy_frag == &zero_address_frag));
|
||||||
know(symbolP->sy_frag);
|
target += S_GET_VALUE(symbolP)
|
||||||
know(!(S_GET_SEGMENT(symbolP) == SEG_ABSOLUTE) ||
|
+ symbolP->sy_frag->fr_address;
|
||||||
symbolP->sy_frag==&zero_address_frag );
|
} /* if we have a symbol */
|
||||||
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. */
|
|
||||||
|
|
||||||
growth -= stretch; /* This is an absolute growth factor */
|
know(fragP->fr_next);
|
||||||
break;
|
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:
|
if (symbolP) {
|
||||||
{
|
know((S_GET_SEGMENT(symbolP) == SEG_ABSOLUTE) ||
|
||||||
register const relax_typeS * this_type;
|
(S_GET_SEGMENT(symbolP) == SEG_DATA) ||
|
||||||
register const relax_typeS * start_type;
|
(S_GET_SEGMENT(symbolP) == SEG_TEXT));
|
||||||
register relax_substateT next_state;
|
know(symbolP->sy_frag);
|
||||||
register relax_substateT this_state;
|
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
|
aim = target - address - fragP->fr_fix;
|
||||||
= md_relax_table + (this_state = fragP->fr_subtype);
|
/* The displacement is affected by the instruction size
|
||||||
target = offset;
|
* for the 32k architecture. I think we ought to be able
|
||||||
if (symbolP)
|
* to add fragP->fr_pcrel_adjust in all cases (it should be
|
||||||
{
|
* zero if not used), but just in case it breaks something
|
||||||
know((S_GET_SEGMENT(symbolP) == SEG_ABSOLUTE) ||
|
* else we'll put this inside #ifdef NS32K ... #endif
|
||||||
(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
|
|
||||||
*/
|
|
||||||
#ifdef TC_NS32K
|
#ifdef TC_NS32K
|
||||||
aim += fragP->fr_pcrel_adjust;
|
aim += fragP->fr_pcrel_adjust;
|
||||||
#endif /* TC_NS32K */
|
#endif /* TC_NS32K */
|
||||||
|
|
||||||
if (aim < 0)
|
if (aim < 0) {
|
||||||
{
|
/* Look backwards. */
|
||||||
/* Look backwards. */
|
for (next_state = this_type->rlx_more; next_state; ) {
|
||||||
for (next_state = this_type->rlx_more; next_state; )
|
if (aim >= this_type->rlx_backward) {
|
||||||
{
|
next_state = 0;
|
||||||
if (aim >= this_type->rlx_backward)
|
} else { /* Grow to next state. */
|
||||||
next_state = 0;
|
this_type = md_relax_table + (this_state = next_state);
|
||||||
else
|
next_state = this_type->rlx_more;
|
||||||
{ /* Grow to next state. */
|
}
|
||||||
this_type = md_relax_table + (this_state = next_state);
|
}
|
||||||
next_state = this_type->rlx_more;
|
} else {
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#ifdef DONTDEF
|
#ifdef DONTDEF
|
||||||
/* JF these next few lines of code are for the mc68020 which can't handle short
|
/* 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! */
|
offsets of zero in branch instructions. What a kludge! */
|
||||||
if (aim==0 && this_state==(1<<2+0)) { /* FOO hard encoded from m.c */
|
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 */
|
aim=this_type->rlx_forward+1; /* Force relaxation into word mode */
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/* JF end of 68020 code */
|
/* JF end of 68020 code */
|
||||||
/* Look forwards. */
|
/* Look forwards. */
|
||||||
for (next_state = this_type->rlx_more; next_state; )
|
for (next_state = this_type->rlx_more; next_state; ) {
|
||||||
{
|
if (aim <= this_type->rlx_forward) {
|
||||||
if (aim <= this_type->rlx_forward)
|
next_state = 0;
|
||||||
next_state = 0;
|
} else { /* Grow to next state. */
|
||||||
else
|
this_type = md_relax_table + (this_state = next_state);
|
||||||
{ /* Grow to next state. */
|
next_state = this_type->rlx_more;
|
||||||
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;
|
|
||||||
|
|
||||||
default:
|
if ((growth = this_type->rlx_length - start_type->rlx_length) != 0)
|
||||||
BAD_CASE( fragP->fr_type );
|
fragP->fr_subtype = this_state;
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (growth) {
|
|
||||||
stretch += growth;
|
|
||||||
stretched++;
|
|
||||||
}
|
|
||||||
} /* For each frag in the segment. */
|
|
||||||
} while (stretched); /* Until nothing further to relax. */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
break;
|
||||||
* We now have valid fr_address'es for each frag.
|
} /* 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'
|
* Relax_align. Advance location counter to next address that has 'alignment'
|
||||||
* lowest order bits all 0s.
|
* lowest order bits all 0s.
|
||||||
@ -895,7 +950,7 @@ register long alignment; /* Alignment (binary). */
|
|||||||
new_address = (address + mask) & (~ mask);
|
new_address = (address + mask) & (~ mask);
|
||||||
return (new_address - address);
|
return (new_address - address);
|
||||||
} /* relax_align() */
|
} /* relax_align() */
|
||||||
|
|
||||||
/* fixup_segment()
|
/* fixup_segment()
|
||||||
|
|
||||||
Go through all the fixS's in a segment and see which ones can be
|
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 char pcrel;
|
||||||
register fragS *fragP;
|
register fragS *fragP;
|
||||||
register segT add_symbol_segment = SEG_ABSOLUTE;
|
register segT add_symbol_segment = SEG_ABSOLUTE;
|
||||||
fixS *topP = fixP;
|
|
||||||
|
|
||||||
|
|
||||||
seg_reloc_count = 0;
|
seg_reloc_count = 0;
|
||||||
@ -1093,12 +1147,16 @@ segT this_segment_type; /* N_TYPE bits for segment. */
|
|||||||
|
|
||||||
#ifdef OBJ_COFF
|
#ifdef OBJ_COFF
|
||||||
#ifdef TC_I960
|
#ifdef TC_I960
|
||||||
/* two relocs per callj under coff. */
|
{
|
||||||
for (fixP = topP; fixP; fixP = fixP->fx_next) {
|
fixS *topP = fixP;
|
||||||
if (fixP->fx_callj && fixP->fx_addsy != 0) {
|
|
||||||
++seg_reloc_count;
|
/* two relocs per callj under coff. */
|
||||||
} /* if callj and not already fixed. */
|
for (fixP = topP; fixP; fixP = fixP->fx_next) {
|
||||||
} /* for each fix */
|
if (fixP->fx_callj && fixP->fx_addsy != 0) {
|
||||||
|
++seg_reloc_count;
|
||||||
|
} /* if callj and not already fixed. */
|
||||||
|
} /* for each fix */
|
||||||
|
}
|
||||||
#endif /* TC_I960 */
|
#endif /* TC_I960 */
|
||||||
#endif /* OBJ_COFF */
|
#endif /* OBJ_COFF */
|
||||||
return(seg_reloc_count);
|
return(seg_reloc_count);
|
||||||
|
Reference in New Issue
Block a user