From 8f287ee72236774216a11a3062f9a26dc8dc66b6 Mon Sep 17 00:00:00 2001 From: ggn Date: Thu, 9 Jan 2020 11:40:02 +0200 Subject: [PATCH 1/1] Introducing new switch -fr which outputs binaries assembled at a given address. --- direct.c | 17 +++++- docs/rmac.rst | 32 +++++++---- mark.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++ mark.h | 1 + object.c | 48 +++++++++++++++- rmac.c | 15 +++-- rmac.h | 4 +- sect.c | 13 +---- 8 files changed, 251 insertions(+), 34 deletions(-) diff --git a/direct.c b/direct.c index b3f51f3..4e9cffd 100644 --- a/direct.c +++ b/direct.c @@ -154,7 +154,7 @@ int (*dirtab[])() = { d_nofpu, // 65 nofpu d_opt, // 66 .opt d_objproc, // 67 .objproc - d_dsm, // 68 .dsm + (void *)d_dsm, // 68 .dsm }; @@ -221,8 +221,8 @@ int d_org(void) { uint64_t address; - if (!rgpu && !rdsp && !robjproc && !m6502 && !dsp56001) - return error(".org permitted only in GPU/DSP/OP, 56001 and 6502 sections"); + if (!rgpu && !rdsp && !robjproc && !m6502 && !dsp56001 && !(obj_format == RAW)) + return error(".org permitted only in GPU/DSP/OP, 56001, 6502 and 68k (with -fr switch) sections"); // M56K can leave the expression off the org for some reason :-/ // (It's because the expression is non-standard, and so we have to look at @@ -346,6 +346,17 @@ int d_org(void) // N.B.: It seems that by enabling this, even though it works elsewhere, will cause symbols to royally fuck up. Will have to do some digging to figure out why. // orgactive = 1; } + else + { + // If we get here we assume it's 68k with RAW output, so this is allowed + if (orgactive) + { + return error("In 68k mode only one .org statement is allowed"); + } + + org68k_address = address; + org68k_active = 1; + } ErrorIfNotAtEOL(); return 0; diff --git a/docs/rmac.rst b/docs/rmac.rst index aeb1df4..0a2e737 100644 --- a/docs/rmac.rst +++ b/docs/rmac.rst @@ -4,7 +4,7 @@ RMAC ===================== Reference Manual ================ -version 2.0.4 +version 2.0.8 ============= © and notes @@ -123,6 +123,7 @@ Switch Description -fa ALCYON output object file format (implied when **-ps** is enabled). -fb BSD COFF output object file format. -fe ELF output object file format. +-fr Absolute address. Source code is required to have one .org statement. -fx Atari 800 com/exe/xex output object file format. -i\ *path* Set include-file directory search path. -l\ *[file[prn]]* Construct and direct assembly listing to the specified file. @@ -153,8 +154,8 @@ Switch Description -o\ *file[.o]* Direct object code output to the specified file. +/~oall Turn all optimisations on/off -+o\ *0-7* Enable specific optimisation -~o\ *0-7* Disable specific optimisation ++o\ *0-9* Enable specific optimisation +~o\ *0-9* Disable specific optimisation `0: Absolute long adddresses to word` @@ -625,9 +626,15 @@ and may not be used as symbols (e.g. labels, equates, or the names of macros): r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 rl3 r14 ri5 6502: - **TODO** + x y a DSP56001: - **TODO** + x x0 x1 x2 y y0 y1 y2 + a a0 a1 a2 b b0 b1 b2 ab ba + mr omr la lc ssh ssl ss + n0 n1 n2 n3 n4 n5 n6 n7 + m0 m1 m2 m3 m4 m5 m6 m7 + r0 r1 r2 r3 r4 r5 r6 r7 + `Constants`_ '''''''''''' @@ -998,6 +1005,13 @@ described in the chapter on `6502 Support`_. Switch to Motorola DSP56001 mode. +**.org** *location* [*X:*/*Y:*/*P:*/*L:*] + This directive sets the value of the location counter (or **pc**) to location, an + expression that must be defined and absolute. It is legal to use the directive in + the following modes: 6502, Tom, Jerry, OP, 56001 and 680x0 (only with -fr switch). + Especially for the 56001 mode the *location* field **must** be prefixed with the + intended section (*X:*, *Y:*, *P:* or *L:*). + **.abs** [*location*] Start an absolute section, beginning with the specified location (or zero, if @@ -1913,7 +1927,7 @@ Atari Falcon XBIOS) and *.p56* (binary equivalent of *.lod*) - Motorola's assembler allows reordering of addressing modes **x:**, **x:r**, **r:y**, **x:y**. rmac will only accept syntax as is defined on the reference manual. -- In **l:** section a dc value cannot be 12 hex digits like Motorola's assmebler. +- In **L:** section a dc value cannot be 12 hex digits like Motorola's assmebler. Instead, the value needs to be split into two parts separated by **:**. `6502 Support`_ @@ -1966,7 +1980,7 @@ y,\ *expr* indexed Y This directive leaves the 6502 segment and returns to the 68000's text segment. 68000 instructions may be assembled as normal. **.org** *location* - This directive is only legal in the 6502 section. It sets the value of the location + This directive sets the value of the location counter (or **pc**) to location, an expression that must be defined, absolute, and less than $10000. @@ -2084,10 +2098,6 @@ order, along with a short description of what may have caused the problem. You tried to use ``.init`` in the BSS or ABS section. -**.org permitted only in .6502 section** - - You tried to use ``.org`` in a 68000 section. - **Cannot create:** *filename* The assembler could not create the indicated filename. diff --git a/mark.c b/mark.c index 6d69c6a..ebd7983 100644 --- a/mark.c +++ b/mark.c @@ -508,6 +508,161 @@ printf(" rsize = $%X\n", rsize); } +// +// Make mark image for RAW file +// +uint32_t MarkABSImage(uint8_t * mp, uint32_t siz, uint32_t tsize, int reqseg) +{ + uint16_t from = 0; // Section fixups are currently FROM + uint32_t rsize = 0; // Relocation table size (written to mp) + int validsegment = 0; // We are not yet in a valid segment... + + // Initialize relocation table point (for D_foo macros) + chptr = mp; + + // Run through all the relocation mark chunks + for(MCHUNK * mch=firstmch; mch!=NULL; mch=mch->mcnext) + { + for (PTR p = mch->mcptr;;) + { + SYM * symbol = NULL; + uint16_t w = *p.wp++; // Next mark entry + + // If we hit the end of a chunk, go get the next one + if (w & MCHEND) + break; + + // Get the rest of the mark record + uint32_t loc = *p.lp++; // Mark location + + // Maybe change "from" section + if (w & MCHFROM) + { + from = *p.wp++; + + if (((reqseg == TEXT) && (from == TEXT)) + || ((reqseg == DATA) && (from == DATA))) + validsegment = 1; + else + validsegment = 0; + } + + // Maybe includes a symbol + if (w & MSYMBOL) + symbol = *p.sy++; + + if (!validsegment) + continue; + + uint32_t rflag = 0x00000040; // Absolute relocation + + if (w & MPCREL) + rflag = 0x000000A0; // PC-relative relocation + + // This flag tells the linker to WORD swap the LONG when doing the + // relocation. + if (w & MMOVEI) + rflag |= 0x00000001; + + // This tells the linker to do a WORD relocation (otherwise it + // defaults to doing a LONG, throwing things off for WORD sized + // fixups) + if (!(w & (MLONG | MQUAD))) + rflag |= 0x00000002; + + // Tell the linker that the fixup is an OL QUAD data address + if (w & MQUAD) + rflag |= 0x00000004; + + if (symbol != NULL) + { + return error("Unresolved symbol when outputting raw image"); + } + else + { + w &= TDB; // Set reloc flags to segment + + switch (w) + { + case TEXT: rflag |= 0x00000400; break; + case DATA: rflag |= 0x00000600; break; + case BSS: rflag |= 0x00000800; break; + } + + // Fix relocation by adding in start of TEXT segment, since it's + // currently relative to the start of the DATA (or BSS) segment + uint8_t * dp = objImage + loc; + uint32_t olBitsSave = 0; + + // Bump the start of the section if it's DATA (& not TEXT) + if (from == DATA) + dp += tsize; + + uint32_t diff = (rflag & 0x02 ? GETBE16(dp, 0) : GETBE32(dp, 0)); + + if (w & (DATA | BSS)) + { + // Special handling for OP (data addr) relocation... + if (rflag & 0x04) + { + olBitsSave = diff & 0x7FF; + diff = (diff & 0xFFFFF800) >> 8; + } + + if (rflag & 0x01) + diff = WORDSWAP32(diff); + + diff += sect[TEXT].sloc; + + if (w == BSS) + diff += sect[DATA].sloc; + } + if ((rflag & 0x02) == 0) + { + diff += org68k_address; + } + + if (rflag & 0x01) + diff = WORDSWAP32(diff); + + // Make sure to deposit the correct size payload + // Check comments in MarkBSDImage for more candid moments + if (rflag & 0x02) // WORD relocation + { + SETBE16(dp, 0, diff); + } + else if (rflag & 0x04) // OP data address relocation + { + // We do it this way because we might have an offset + // that is not a multiple of 8 and thus we need this in + // place to prevent a bad address at link time. :-P As + // a consequence of this, the highest address we can + // have here is $1FFFF8. + uint32_t diffsave = diff; + diff = ((diff & 0x001FFFFF) << 11) | olBitsSave; + SETBE32(dp, 0, diff); + // But we need those 3 bits, otherwise we can get in + // trouble with things like OL data that is in the cart + // space, and BOOM! So the 2nd phrase of the fixup (it + // will *always* have a 2nd phrase) has a few spare + // bits, we chuck them in there. + uint32_t p2 = GETBE32(dp, 8); + p2 &= 0x1FFFFFFF; + p2 |= (diffsave & 0x00E00000) << 8; + SETBE32(dp, 8, p2); + } + else // LONG relocation + { + SETBE32(dp, 0, diff); + } + } + } + } + + return OK; +} + + // // Make relocation record for ELF .o file. // Returns the size of the relocation record. diff --git a/mark.h b/mark.h index c408b14..e185c24 100644 --- a/mark.h +++ b/mark.h @@ -52,6 +52,7 @@ uint32_t AllocateMark(void); uint32_t MarkImage(register uint8_t * mp, uint32_t siz, uint32_t tsize, int okflag); uint32_t MarkBSDImage(uint8_t *, uint32_t, uint32_t, int); uint32_t CreateELFRelocationRecord(uint8_t *, uint8_t *, uint16_t section); +uint32_t MarkABSImage(uint8_t * mp, uint32_t siz, uint32_t tsize, int reqseg); #endif // __MARK_H__ diff --git a/object.c b/object.c index 0828eff..7545866 100644 --- a/object.c +++ b/object.c @@ -327,7 +327,9 @@ int WriteObject(int fd) // Write requested object file... if ((obj_format == BSD) || ((obj_format == ALCYON) && (prg_flag == 0))) - { + { + ch_size = 0; + // Force BSD format (if it was ALCYON format) obj_format = BSD; @@ -425,6 +427,8 @@ int WriteObject(int fd) } else if (obj_format == ALCYON) { + ch_size = 0; + if (verb_flag) { if (prg_flag) @@ -435,6 +439,7 @@ int WriteObject(int fd) // Assign index numbers to the symbols, get # of symbols (we assume // that all symbols can potentially be extended, hence the x28) + // (To clarify: 28 bytes is the size of an extended symbol) uint32_t symbolMaxSize = sy_assign(NULL, NULL) * 28; // Alloc memory for header + text + data, symbol and relocation @@ -807,13 +812,52 @@ for(int j=0; jchnext) + { + memcpy(p, cp->chptr, cp->ch_size); + p += cp->ch_size; + } + } + + if (MarkABSImage(buf, tds, sect[TEXT].sloc, TEXT) != OK) // Do TEXT relocation table + { + return ERROR; + } + if (MarkABSImage(buf, tds, sect[TEXT].sloc, DATA) != OK) // Do DATA relocation table + { + return ERROR; + } + // Write out the header + text & data + symbol table (if any) + unused = write(fd, buf, tds); + + } return 0; } diff --git a/rmac.c b/rmac.c index 1111d6d..087225e 100644 --- a/rmac.c +++ b/rmac.c @@ -55,7 +55,8 @@ char defname[] = "noname.o"; // Default output filename int optim_flags[OPT_COUNT]; // Specific optimisations on/off matrix int activecpu = CPU_68000; // Active 68k CPU (68000 by default) int activefpu = FPU_NONE; // Active FPU (none by default) - +int org68k_active = 0; // .org switch for 68k (only with RAW output format) +uint32_t org68k_address; // .org for 68k // // Convert a string to uppercase @@ -152,6 +153,7 @@ void DisplayHelp(void) " p: P56 (use this for DSP56001 only)\n" " l: LOD (use this for DSP56001 only)\n" " x: com/exe/xex (Atari 800)\n" + " r: absolute address" " -i[path] Directory to search for include files\n" " -l[filename] Create an output listing file\n" " -l*[filename] Create an output listing file without pagination\n" @@ -174,10 +176,9 @@ void DisplayHelp(void) " ~o[value] Turn a specific optimisation off\n" " +oall Turn all optimisations on\n" " ~oall Turn all optimisations off\n" - " -p Create an ST .prg (without symbols)\n" - " -ps Create an ST .prg (with symbols)\n" - " -px Create an ST .prg (with exsymbols)\n" - " Forces -fa\n" + " -p Create an ST .prg (without symbols). Forces -fa\n" + " -ps Create an ST .prg (with symbols). Forces -fa\n" + " -px Create an ST .prg (with exsymbols). Forces -fa\n" " -r[size] Pad segments to boundary size specified\n" " w: word (2 bytes, default alignment)\n" " l: long (4 bytes)\n" @@ -368,6 +369,10 @@ int Process(int argc, char ** argv) case 'X': obj_format = XEX; break; + case 'r': // -fr = Absolute address + case 'R': + obj_format = RAW; + break; default: printf("-f: unknown object format specified\n"); errcnt++; diff --git a/rmac.h b/rmac.h index 52fb92d..5ae6d13 100644 --- a/rmac.h +++ b/rmac.h @@ -177,12 +177,12 @@ enum { ALCYON, // Alcyon/DRI C object format -MWC, // Mark Williams object format BSD, // BSD object format ELF, // ELF object format LOD, // DSP 56001 object format P56, // DSP 56001 object format XEX, // COM/EXE/XEX/whatever a8 object format +RAW, // Output at absolute address }; // Assembler token @@ -318,6 +318,8 @@ extern LONG PRGFLAGS; extern int optim_flags[OPT_COUNT]; extern int activecpu; extern int activefpu; +extern uint32_t org68k_address; +extern int org68k_active; // Exported functions void strtoupper(char * s); diff --git a/sect.c b/sect.c index 4dc7032..0ea53a8 100644 --- a/sect.c +++ b/sect.c @@ -450,9 +450,6 @@ int ResolveFixups(int sno) // from the location (that will happen in the linker when the external // reference is resolved). // - // MWC expects PC-relative things to have the LOC subtracted from the - // value, if the value is external (that is, undefined at this point). - // // PC-relative fixups must be DEFINED and either in the same section // (whereupon the subtraction takes place) or ABS (with no subtract). if ((dw & FU_PCREL) || (dw & FU_PCRELX)) @@ -470,7 +467,7 @@ int ResolveFixups(int sno) else if (tdb) { // Allow cross-section PCREL fixups in Alcyon mode - if (prg_flag) + if (prg_flag || (obj_format == RAW)) { switch (tdb) { @@ -504,14 +501,6 @@ int ResolveFixups(int sno) if (sbra_flag && (dw & FU_LBRA) && (eval + 0x80 < 0x100)) warn("unoptimized short branch"); } - else if (obj_format == MWC) - { - eval -= loc; - - // In this instruction the PC is located a DWORD away - if (dw & FU_PCRELX) - eval += 2; - } // Be sure to clear any TDB flags, since we handled it just now tdb = 0; -- 2.37.2