From f6e504fe91d1dd1c8ddc46fe0971a9bde5309573 Mon Sep 17 00:00:00 2001 From: "K. Richard Pixley" Date: Sat, 27 Jul 1991 02:34:20 +0000 Subject: [PATCH] Polishing m68k support. --- gas/config/ho-sun3.h | 2 - gas/config/obj-aout.h | 19 +- gas/config/tc-a29k.c | 3 +- gas/config/tc-m68k.c | 552 ++++++++++++++++---------------- gas/write.c | 720 +++++++++++++++++++++++------------------- 5 files changed, 672 insertions(+), 624 deletions(-) diff --git a/gas/config/ho-sun3.h b/gas/config/ho-sun3.h index 33b74c37d74..41d2f96825d 100644 --- a/gas/config/ho-sun3.h +++ b/gas/config/ho-sun3.h @@ -2,6 +2,4 @@ #include -extern int sprintf(); - /* end of ho-sun3.h */ diff --git a/gas/config/obj-aout.h b/gas/config/obj-aout.h index d2152db51a9..44e2c3a5346 100644 --- a/gas/config/obj-aout.h +++ b/gas/config/obj-aout.h @@ -5,7 +5,7 @@ This file is part of GAS, the GNU Assembler. GAS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 1, +published by the Free Software Foundation; either version 2, or (at your option) any later version. GAS is distributed in the hope that it will be useful, but @@ -133,13 +133,15 @@ typedef struct nlist obj_symbol_type; /* Symbol table entry */ /* File header macro and type definition */ -#define H_GET_FILE_SIZE(h) (sizeof(struct exec) + \ - H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h) + \ - H_GET_SYMBOL_TABLE_SIZE(h) + \ - H_GET_TEXT_RELOCATION_SIZE(h) + \ - H_GET_DATA_RELOCATION_SIZE(h) + \ - (h)->string_table_size) +#define H_GET_FILE_SIZE(h) (H_GET_HEADER_SIZE(h) \ + + H_GET_TEXT_SIZE(h) \ + + H_GET_DATA_SIZE(h) \ + + H_GET_SYMBOL_TABLE_SIZE(h) \ + + H_GET_TEXT_RELOCATION_SIZE(h) \ + + H_GET_DATA_RELOCATION_SIZE(h) \ + + H_GET_STRING_SIZE(h)) +#define H_GET_HEADER_SIZE(h) (sizeof(struct exec)) #define H_GET_TEXT_SIZE(h) ((h)->header.a_text) #define H_GET_DATA_SIZE(h) ((h)->header.a_data) #define H_GET_BSS_SIZE(h) ((h)->header.a_bss) @@ -149,9 +151,12 @@ typedef struct nlist obj_symbol_type; /* Symbol table entry */ #define H_GET_MAGIC_NUMBER(h) ((h)->header.a_info) #define H_GET_ENTRY_POINT(h) ((h)->header.a_entry) #define H_GET_STRING_SIZE(h) ((h)->string_table_size) +#define H_GET_LINENO_SIZE(h) (0) + #ifdef EXEC_MACHINE_TYPE #define H_GET_MACHINE_TYPE(h) ((h)->header.a_machtype) #endif /* EXEC_MACHINE_TYPE */ + #ifdef EXEC_VERSION #define H_GET_VERSION(h) ((h)->header.a_version) #endif /* EXEC_VERSION */ diff --git a/gas/config/tc-a29k.c b/gas/config/tc-a29k.c index cee99f922e2..fecdc5d2e9d 100644 --- a/gas/config/tc-a29k.c +++ b/gas/config/tc-a29k.c @@ -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"); diff --git a/gas/config/tc-m68k.c b/gas/config/tc-m68k.c index c2ba22831c6..ea60b6935bb 100644 --- a/gas/config/tc-m68k.c +++ b/gas/config/tc-m68k.c @@ -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, diff --git a/gas/write.c b/gas/write.c index a0b36c35173..7dce445d8f6 100644 --- a/gas/write.c +++ b/gas/write.c @@ -5,7 +5,7 @@ This file is part of GAS, the GNU Assembler. GAS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) +the Free Software Foundation; either version 2, or (at your option) any later version. GAS is distributed in the hope that it will be useful, @@ -115,7 +115,6 @@ enum reloc_type r_type; /* Relocation type */ fixP->fx_offset = offset; fixP->fx_pcrel = pcrel; fixP->fx_r_type = r_type; - fixP->fx_next = NULL; /* JF these 'cuz of the NS32K stuff */ fixP->fx_im_disp = 0; @@ -123,15 +122,32 @@ enum reloc_type r_type; /* Relocation type */ fixP->fx_bsr = 0; fixP->fx_bit_fixP = 0; + /* usually, we want relocs sorted numerically, but while + comparing to older versions of gas that have relocs + reverse sorted, it is convenient to have this compile + time option. xoxorich. */ + +#ifdef REVERSE_SORT_RELOCS + + fixP->fx_next = *seg_fix_rootP; + *seg_fix_rootP = fixP; + +#else /* REVERSE_SORT_RELOCS */ + + fixP->fx_next = NULL; + if (*seg_fix_tailP) (*seg_fix_tailP)->fx_next = fixP; else *seg_fix_rootP = fixP; *seg_fix_tailP = fixP; + +#endif /* REVERSE_SORT_RELOCS */ + fixP->fx_callj = 0; return fixP; } - + void write_object_file() { register struct frchain * frchainP; /* Track along all frchains. */ register fragS * fragP; /* Track along all frags. */ @@ -190,7 +206,7 @@ void write_object_file() { /* know( frags . obstack_c_base == frags . obstack_c_next_free ); */ /* Above shows we haven't left a half-completed object on obstack. */ } /* walk the frag chain */ - + /* * From now on, we don't care about sub-segments. * Build one frag chain for each segment. Linked thru fr_next. @@ -240,8 +256,8 @@ void write_object_file() { */ know(text_last_frag->fr_type == rs_fill && text_last_frag->fr_offset == 0); - H_SET_TEXT_SIZE(&headers,text_last_frag->fr_address); - text_last_frag->fr_address=H_GET_TEXT_SIZE(&headers); + H_SET_TEXT_SIZE(&headers, text_last_frag->fr_address); + text_last_frag->fr_address = H_GET_TEXT_SIZE(&headers); /* * Join the 2 segments into 1 huge segment. @@ -251,20 +267,20 @@ void write_object_file() { * Determine a_data [length of data segment]. */ if (data_frag_root) { - register relax_addressT slide; + register relax_addressT slide; - know( text_last_frag->fr_type == rs_fill && text_last_frag->fr_offset == 0 ); + know((text_last_frag->fr_type == rs_fill) + && (text_last_frag->fr_offset == 0)); + H_SET_DATA_SIZE(&headers, data_last_frag->fr_address); data_last_frag->fr_address = H_GET_DATA_SIZE(&headers); slide = H_GET_TEXT_SIZE(&headers); /* & in file of the data segment. */ - for (fragP = data_frag_root; - fragP; - fragP = fragP->fr_next) - { - fragP->fr_address += slide; - } - know( text_last_frag ); + for (fragP = data_frag_root; fragP; fragP = fragP->fr_next) { + fragP->fr_address += slide; + } /* for each data frag */ + + know(text_last_frag != 0); text_last_frag->fr_next = data_frag_root; } else { H_SET_DATA_SIZE(&headers,0); @@ -321,25 +337,25 @@ void write_object_file() { case rs_align: case rs_org: fragP->fr_type = rs_fill; - know( fragP->fr_var == 1 ); - know( fragP->fr_next ); - fragP->fr_offset - = fragP->fr_next->fr_address - - fragP->fr_address - - fragP->fr_fix; + know(fragP->fr_var == 1); + know(fragP->fr_next != NULL); + + fragP->fr_offset = (fragP->fr_next->fr_address + - fragP->fr_address + - fragP->fr_fix); break; case rs_fill: break; case rs_machine_dependent: - md_convert_frag (fragP); + md_convert_frag(&headers, fragP); /* * After md_convert_frag, we make the frag into a ".space 0". * Md_convert_frag() should set up any fixSs and constants * required. */ - frag_wane (fragP); + frag_wane(fragP); break; #ifndef WORKING_DOT_WORD @@ -463,13 +479,13 @@ void write_object_file() { /* FIXME move this stuff into the pre-write-hook */ H_SET_MAGIC_NUMBER(&headers, magic_number_for_object_file); - H_SET_ENTRY_POINT(&headers,0); + H_SET_ENTRY_POINT(&headers, 0); #ifdef EXEC_MACHINE_TYPE - H_SET_MACHINE_TYPE(&headers,EXEC_MACHINE_TYPE); + H_SET_MACHINE_TYPE(&headers, EXEC_MACHINE_TYPE); #endif #ifdef EXEC_VERSION - H_SET_VERSION(&headers,EXEC_VERSION); + H_SET_VERSION(&headers, EXEC_VERSION); #endif obj_pre_write_hook(&headers); /* extra coff stuff */ @@ -493,29 +509,42 @@ void write_object_file() { output_file_create(out_file_name); obj_header_append(&next_object_file_charP, &headers); - + know((next_object_file_charP - the_object_file) == H_GET_HEADER_SIZE(&headers)); + /* * Emit code. */ for (fragP = text_frag_root; fragP; fragP = fragP->fr_next) { - register long count; - register char * fill_literal; - register long fill_size; + register long count; + register char *fill_literal; + register long fill_size; - know( fragP->fr_type == rs_fill ); - append (& next_object_file_charP, fragP->fr_literal, (unsigned long)fragP->fr_fix); - fill_literal= fragP->fr_literal + fragP->fr_fix; - fill_size = fragP->fr_var; - know( fragP->fr_offset >= 0 ); - for (count = fragP->fr_offset; count; count --) - append (& next_object_file_charP, fill_literal, (unsigned long)fill_size); + know(fragP->fr_type == rs_fill); + append(&next_object_file_charP, fragP->fr_literal, (unsigned long) fragP->fr_fix); + fill_literal = fragP->fr_literal + fragP->fr_fix; + fill_size = fragP->fr_var; + know(fragP->fr_offset >= 0); + + for (count = fragP->fr_offset; count; count--) { + append(&next_object_file_charP, fill_literal, (unsigned long) fill_size); + } /* for each */ + } /* for each code frag. */ + + know((next_object_file_charP - the_object_file) + == (H_GET_HEADER_SIZE(&headers) + + H_GET_TEXT_SIZE(&headers) + + H_GET_DATA_SIZE(&headers))); /* * Emit relocations. */ obj_emit_relocations(&next_object_file_charP, text_fix_root, (relax_addressT)0); - + know((next_object_file_charP - the_object_file) + == (H_GET_HEADER_SIZE(&headers) + + H_GET_TEXT_SIZE(&headers) + + H_GET_DATA_SIZE(&headers) + + H_GET_TEXT_RELOCATION_SIZE(&headers))); #ifdef TC_I960 /* Make addresses in data relocation directives relative to beginning of * first data fragment, not end of last text fragment: alignment of the @@ -526,16 +555,38 @@ void write_object_file() { obj_emit_relocations(&next_object_file_charP, data_fix_root, text_last_frag->fr_address); #endif /* TC_I960 */ + know((next_object_file_charP - the_object_file) + == (H_GET_HEADER_SIZE(&headers) + + H_GET_TEXT_SIZE(&headers) + + H_GET_DATA_SIZE(&headers) + + H_GET_TEXT_RELOCATION_SIZE(&headers) + + H_GET_DATA_RELOCATION_SIZE(&headers))); + /* * Emit line number entries. */ OBJ_EMIT_LINENO(&next_object_file_charP, lineno_rootP, the_object_file); + know((next_object_file_charP - the_object_file) + == (H_GET_HEADER_SIZE(&headers) + + H_GET_TEXT_SIZE(&headers) + + H_GET_DATA_SIZE(&headers) + + H_GET_TEXT_RELOCATION_SIZE(&headers) + + H_GET_DATA_RELOCATION_SIZE(&headers) + + H_GET_LINENO_SIZE(&headers))); /* * Emit symbols. */ obj_emit_symbols(&next_object_file_charP, symbol_rootP); - + know((next_object_file_charP - the_object_file) + == (H_GET_HEADER_SIZE(&headers) + + H_GET_TEXT_SIZE(&headers) + + H_GET_DATA_SIZE(&headers) + + H_GET_TEXT_RELOCATION_SIZE(&headers) + + H_GET_DATA_RELOCATION_SIZE(&headers) + + H_GET_LINENO_SIZE(&headers) + + H_GET_SYMBOL_TABLE_SIZE(&headers))); + /* * Emit strings. */ @@ -544,6 +595,16 @@ void write_object_file() { obj_emit_strings(&next_object_file_charP); } /* only if we have a string table */ + know((next_object_file_charP - the_object_file) + == (H_GET_HEADER_SIZE(&headers) + + H_GET_TEXT_SIZE(&headers) + + H_GET_DATA_SIZE(&headers) + + H_GET_TEXT_RELOCATION_SIZE(&headers) + + H_GET_DATA_RELOCATION_SIZE(&headers) + + H_GET_LINENO_SIZE(&headers) + + H_GET_SYMBOL_TABLE_SIZE(&headers) + + H_GET_STRING_SIZE(&headers))); + know(next_object_file_charP == the_object_file + object_file_size); /* Write the data to the file */ output_file_append(the_object_file,object_file_size,out_file_name); @@ -581,303 +642,297 @@ void write_object_file() { #ifndef VMS static #endif /* not VMS */ -void relax_segment(segment_frag_root, segment_type) +void relax_segment(segment_frag_root, segment) struct frag * segment_frag_root; - segT segment_type; /* SEG_DATA or SEG_TEXT */ + segT segment; /* SEG_DATA or SEG_TEXT */ { - register struct frag * fragP; - register relax_addressT address; - /* register relax_addressT old_address; JF unused */ - /* register relax_addressT new_address; JF unused */ - - know( segment_type == SEG_DATA || segment_type == SEG_TEXT ); - - /* In case md_estimate_size_before_relax() wants to make fixSs. */ - subseg_change(segment_type, 0); - - /* - * For each frag in segment: count and store (a 1st guess of) fr_address. - */ - address = 0; - for ( fragP = segment_frag_root; fragP; fragP = fragP->fr_next ) - { - fragP->fr_address = address; - address += fragP->fr_fix; - switch (fragP->fr_type) - { - 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 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; + /* 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(). - */ - { - 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; - + + 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; + /* 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; + } } - 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_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. */ - - 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; - 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 - */ + 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; + + 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 */ + + 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; + + 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 */ + + 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; - - 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. */ - } + /* 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; + } + } + } - /* - * We now have valid fr_address'es for each frag. - */ + if ((growth = this_type->rlx_length - start_type->rlx_length) != 0) + fragP->fr_subtype = this_state; + + 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); -- 2.30.2