Make @ relative to the start of a ds even at link time

Fix #737
This commit is contained in:
Rangi
2021-02-14 20:53:44 -05:00
committed by Eldred Habert
parent 2bc12447e2
commit ee20d9010e
13 changed files with 74 additions and 72 deletions

View File

@@ -22,7 +22,7 @@ extern struct Section *pSectionList, *pCurrentSection;
void out_RegisterNode(struct FileStackNode *node); void out_RegisterNode(struct FileStackNode *node);
void out_ReplaceNode(struct FileStackNode *node); void out_ReplaceNode(struct FileStackNode *node);
void out_SetFileName(char *s); void out_SetFileName(char *s);
void out_CreatePatch(uint32_t type, struct Expression const *expr, uint32_t ofs, bool isOperand); void out_CreatePatch(uint32_t type, struct Expression const *expr, uint32_t ofs, uint32_t pcShift);
bool out_CreateAssert(enum AssertionType type, struct Expression const *expr, bool out_CreateAssert(enum AssertionType type, struct Expression const *expr,
char const *message, uint32_t ofs); char const *message, uint32_t ofs);
void out_WriteObject(void); void out_WriteObject(void);

View File

@@ -62,11 +62,11 @@ void out_AbsWordGroup(uint8_t const *s, int32_t length);
void out_AbsLongGroup(uint8_t const *s, int32_t length); void out_AbsLongGroup(uint8_t const *s, int32_t length);
void out_Skip(int32_t skip, bool ds); void out_Skip(int32_t skip, bool ds);
void out_String(char const *s); void out_String(char const *s);
void out_RelByte(struct Expression *expr, bool isOperand); void out_RelByte(struct Expression *expr, uint32_t pcShift);
void out_RelBytes(struct Expression *expr, uint32_t n); void out_RelBytes(struct Expression *expr, uint32_t n);
void out_RelWord(struct Expression *expr, bool isOperand); void out_RelWord(struct Expression *expr, uint32_t pcShift);
void out_RelLong(struct Expression *expr, bool isOperand); void out_RelLong(struct Expression *expr, uint32_t pcShift);
void out_PCRelByte(struct Expression *expr, bool isOperand); void out_PCRelByte(struct Expression *expr, uint32_t pcShift);
void out_BinaryFile(char const *s, int32_t startPos); void out_BinaryFile(char const *s, int32_t startPos);
void out_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length); void out_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length);

View File

@@ -34,7 +34,6 @@ struct Patch {
uint32_t pcSectionID; uint32_t pcSectionID;
uint32_t pcOffset; uint32_t pcOffset;
enum PatchType type; enum PatchType type;
bool isOperand;
int32_t rpnSize; int32_t rpnSize;
uint8_t *rpnExpression; uint8_t *rpnExpression;

View File

@@ -99,8 +99,6 @@ enum ExportLevel {
SYMTYPE_EXPORT SYMTYPE_EXPORT
}; };
// Bit 7 is special, not part of the actual patch type
#define PATCH_ISOPERAND 0x80
enum PatchType { enum PatchType {
PATCHTYPE_BYTE, PATCHTYPE_BYTE,
PATCHTYPE_WORD, PATCHTYPE_WORD,

View File

@@ -39,7 +39,6 @@ struct Patch {
struct Section *pcSection; struct Section *pcSection;
uint32_t pcOffset; uint32_t pcOffset;
uint8_t type; uint8_t type;
bool isOperand; // If set, PC is not at the patch's address, but at the byte before
uint32_t nRPNSize; uint32_t nRPNSize;
uint8_t *pRPN; uint8_t *pRPN;
struct Patch *next; struct Patch *next;
@@ -204,17 +203,12 @@ static uint32_t getSectIDIfAny(struct Section const *sect)
static void writepatch(struct Patch const *patch, FILE *f) static void writepatch(struct Patch const *patch, FILE *f)
{ {
assert(patch->src->ID != -1); assert(patch->src->ID != -1);
uint8_t type = patch->type;
if (patch->isOperand)
type |= PATCH_ISOPERAND;
putlong(patch->src->ID, f); putlong(patch->src->ID, f);
putlong(patch->lineNo, f); putlong(patch->lineNo, f);
putlong(patch->nOffset, f); putlong(patch->nOffset, f);
putlong(getSectIDIfAny(patch->pcSection), f); putlong(getSectIDIfAny(patch->pcSection), f);
putlong(patch->pcOffset, f); putlong(patch->pcOffset, f);
putc(type, f); putc(patch->type, f);
putlong(patch->nRPNSize, f); putlong(patch->nRPNSize, f);
fwrite(patch->pRPN, 1, patch->nRPNSize, f); fwrite(patch->pRPN, 1, patch->nRPNSize, f);
} }
@@ -387,7 +381,6 @@ static struct Patch *allocpatch(uint32_t type, struct Expression const *expr, ui
fatalerror("No memory for patch's RPN expression: %s\n", strerror(errno)); fatalerror("No memory for patch's RPN expression: %s\n", strerror(errno));
patch->type = type; patch->type = type;
patch->isOperand = false;
patch->src = node; patch->src = node;
out_RegisterNode(node); out_RegisterNode(node);
patch->lineNo = lexer_GetLineNo(); patch->lineNo = lexer_GetLineNo();
@@ -416,11 +409,15 @@ static struct Patch *allocpatch(uint32_t type, struct Expression const *expr, ui
/* /*
* Create a new patch (includes the rpn expr) * Create a new patch (includes the rpn expr)
*/ */
void out_CreatePatch(uint32_t type, struct Expression const *expr, uint32_t ofs, bool isOperand) void out_CreatePatch(uint32_t type, struct Expression const *expr, uint32_t ofs, uint32_t pcShift)
{ {
struct Patch *patch = allocpatch(type, expr, ofs); struct Patch *patch = allocpatch(type, expr, ofs);
patch->isOperand = isOperand; // If the patch had a quantity of bytes output before it,
// PC is not at the patch's location, but at the location
// before those bytes.
patch->pcOffset -= pcShift;
patch->next = pCurrentSection->patches; patch->next = pCurrentSection->patches;
pCurrentSection->patches = patch; pCurrentSection->patches = patch;
} }

View File

@@ -1122,7 +1122,7 @@ constlist_8bit_entry : %empty {
$$ = true; $$ = true;
} }
| reloc_8bit_no_str { | reloc_8bit_no_str {
out_RelByte(&$1, false); out_RelByte(&$1, 0);
$$ = false; $$ = false;
} }
| string { | string {
@@ -1146,7 +1146,7 @@ constlist_16bit_entry : %empty {
$$ = true; $$ = true;
} }
| reloc_16bit_no_str { | reloc_16bit_no_str {
out_RelWord(&$1, false); out_RelWord(&$1, 0);
$$ = false; $$ = false;
} }
| string { | string {
@@ -1170,7 +1170,7 @@ constlist_32bit_entry : %empty {
$$ = true; $$ = true;
} }
| relocexpr_no_str { | relocexpr_no_str {
out_RelLong(&$1, false); out_RelLong(&$1, 0);
$$ = false; $$ = false;
} }
| string { | string {
@@ -1570,27 +1570,27 @@ cpu_command : z80_adc
z80_adc : T_Z80_ADC op_a_n { z80_adc : T_Z80_ADC op_a_n {
out_AbsByte(0xCE); out_AbsByte(0xCE);
out_RelByte(&$2, true); out_RelByte(&$2, 1);
} }
| T_Z80_ADC op_a_r { out_AbsByte(0x88 | $2); } | T_Z80_ADC op_a_r { out_AbsByte(0x88 | $2); }
; ;
z80_add : T_Z80_ADD op_a_n { z80_add : T_Z80_ADD op_a_n {
out_AbsByte(0xC6); out_AbsByte(0xC6);
out_RelByte(&$2, true); out_RelByte(&$2, 1);
} }
| T_Z80_ADD op_a_r { out_AbsByte(0x80 | $2); } | T_Z80_ADD op_a_r { out_AbsByte(0x80 | $2); }
| T_Z80_ADD op_hl_ss { out_AbsByte(0x09 | ($2 << 4)); } | T_Z80_ADD op_hl_ss { out_AbsByte(0x09 | ($2 << 4)); }
| T_Z80_ADD T_MODE_SP T_COMMA reloc_8bit { | T_Z80_ADD T_MODE_SP T_COMMA reloc_8bit {
out_AbsByte(0xE8); out_AbsByte(0xE8);
out_RelByte(&$4, true); out_RelByte(&$4, 1);
} }
; ;
z80_and : T_Z80_AND op_a_n { z80_and : T_Z80_AND op_a_n {
out_AbsByte(0xE6); out_AbsByte(0xE6);
out_RelByte(&$2, true); out_RelByte(&$2, 1);
} }
| T_Z80_AND op_a_r { out_AbsByte(0xA0 | $2); } | T_Z80_AND op_a_r { out_AbsByte(0xA0 | $2); }
; ;
@@ -1603,11 +1603,11 @@ z80_bit : T_Z80_BIT const_3bit T_COMMA reg_r {
z80_call : T_Z80_CALL reloc_16bit { z80_call : T_Z80_CALL reloc_16bit {
out_AbsByte(0xCD); out_AbsByte(0xCD);
out_RelWord(&$2, true); out_RelWord(&$2, 1);
} }
| T_Z80_CALL ccode T_COMMA reloc_16bit { | T_Z80_CALL ccode T_COMMA reloc_16bit {
out_AbsByte(0xC4 | ($2 << 3)); out_AbsByte(0xC4 | ($2 << 3));
out_RelWord(&$4, true); out_RelWord(&$4, 1);
} }
; ;
@@ -1616,7 +1616,7 @@ z80_ccf : T_Z80_CCF { out_AbsByte(0x3F); }
z80_cp : T_Z80_CP op_a_n { z80_cp : T_Z80_CP op_a_n {
out_AbsByte(0xFE); out_AbsByte(0xFE);
out_RelByte(&$2, true); out_RelByte(&$2, 1);
} }
| T_Z80_CP op_a_r { out_AbsByte(0xB8 | $2); } | T_Z80_CP op_a_r { out_AbsByte(0xB8 | $2); }
; ;
@@ -1650,11 +1650,11 @@ z80_inc : T_Z80_INC reg_r { out_AbsByte(0x04 | ($2 << 3)); }
z80_jp : T_Z80_JP reloc_16bit { z80_jp : T_Z80_JP reloc_16bit {
out_AbsByte(0xC3); out_AbsByte(0xC3);
out_RelWord(&$2, true); out_RelWord(&$2, 1);
} }
| T_Z80_JP ccode T_COMMA reloc_16bit { | T_Z80_JP ccode T_COMMA reloc_16bit {
out_AbsByte(0xC2 | ($2 << 3)); out_AbsByte(0xC2 | ($2 << 3));
out_RelWord(&$4, true); out_RelWord(&$4, 1);
} }
| T_Z80_JP T_MODE_HL { | T_Z80_JP T_MODE_HL {
out_AbsByte(0xE9); out_AbsByte(0xE9);
@@ -1663,11 +1663,11 @@ z80_jp : T_Z80_JP reloc_16bit {
z80_jr : T_Z80_JR reloc_16bit { z80_jr : T_Z80_JR reloc_16bit {
out_AbsByte(0x18); out_AbsByte(0x18);
out_PCRelByte(&$2, true); out_PCRelByte(&$2, 1);
} }
| T_Z80_JR ccode T_COMMA reloc_16bit { | T_Z80_JR ccode T_COMMA reloc_16bit {
out_AbsByte(0x20 | ($2 << 3)); out_AbsByte(0x20 | ($2 << 3));
out_PCRelByte(&$4, true); out_PCRelByte(&$4, 1);
} }
; ;
@@ -1691,13 +1691,13 @@ z80_ldio : T_Z80_LDH T_MODE_A T_COMMA op_mem_ind {
rpn_CheckHRAM(&$4, &$4); rpn_CheckHRAM(&$4, &$4);
out_AbsByte(0xF0); out_AbsByte(0xF0);
out_RelByte(&$4, true); out_RelByte(&$4, 1);
} }
| T_Z80_LDH op_mem_ind T_COMMA T_MODE_A { | T_Z80_LDH op_mem_ind T_COMMA T_MODE_A {
rpn_CheckHRAM(&$2, &$2); rpn_CheckHRAM(&$2, &$2);
out_AbsByte(0xE0); out_AbsByte(0xE0);
out_RelByte(&$2, true); out_RelByte(&$2, 1);
} }
| T_Z80_LDH T_MODE_A T_COMMA c_ind { | T_Z80_LDH T_MODE_A T_COMMA c_ind {
out_AbsByte(0xF2); out_AbsByte(0xF2);
@@ -1723,24 +1723,24 @@ z80_ld : z80_ld_mem
z80_ld_hl : T_Z80_LD T_MODE_HL T_COMMA T_MODE_SP reloc_8bit { z80_ld_hl : T_Z80_LD T_MODE_HL T_COMMA T_MODE_SP reloc_8bit {
out_AbsByte(0xF8); out_AbsByte(0xF8);
out_RelByte(&$5, true); out_RelByte(&$5, 1);
} }
| T_Z80_LD T_MODE_HL T_COMMA reloc_16bit { | T_Z80_LD T_MODE_HL T_COMMA reloc_16bit {
out_AbsByte(0x01 | (REG_HL << 4)); out_AbsByte(0x01 | (REG_HL << 4));
out_RelWord(&$4, true); out_RelWord(&$4, 1);
} }
; ;
z80_ld_sp : T_Z80_LD T_MODE_SP T_COMMA T_MODE_HL { out_AbsByte(0xF9); } z80_ld_sp : T_Z80_LD T_MODE_SP T_COMMA T_MODE_HL { out_AbsByte(0xF9); }
| T_Z80_LD T_MODE_SP T_COMMA reloc_16bit { | T_Z80_LD T_MODE_SP T_COMMA reloc_16bit {
out_AbsByte(0x01 | (REG_SP << 4)); out_AbsByte(0x01 | (REG_SP << 4));
out_RelWord(&$4, true); out_RelWord(&$4, 1);
} }
; ;
z80_ld_mem : T_Z80_LD op_mem_ind T_COMMA T_MODE_SP { z80_ld_mem : T_Z80_LD op_mem_ind T_COMMA T_MODE_SP {
out_AbsByte(0x08); out_AbsByte(0x08);
out_RelWord(&$2, true); out_RelWord(&$2, 1);
} }
| T_Z80_LD op_mem_ind T_COMMA T_MODE_A { | T_Z80_LD op_mem_ind T_COMMA T_MODE_A {
if (optimizeloads && rpn_isKnown(&$2) if (optimizeloads && rpn_isKnown(&$2)
@@ -1750,7 +1750,7 @@ z80_ld_mem : T_Z80_LD op_mem_ind T_COMMA T_MODE_SP {
rpn_Free(&$2); rpn_Free(&$2);
} else { } else {
out_AbsByte(0xEA); out_AbsByte(0xEA);
out_RelWord(&$2, true); out_RelWord(&$2, 1);
} }
} }
; ;
@@ -1767,7 +1767,7 @@ z80_ld_rr : T_Z80_LD reg_rr T_COMMA T_MODE_A {
z80_ld_r : T_Z80_LD reg_r T_COMMA reloc_8bit { z80_ld_r : T_Z80_LD reg_r T_COMMA reloc_8bit {
out_AbsByte(0x06 | ($2 << 3)); out_AbsByte(0x06 | ($2 << 3));
out_RelByte(&$4, true); out_RelByte(&$4, 1);
} }
| T_Z80_LD reg_r T_COMMA reg_r { | T_Z80_LD reg_r T_COMMA reg_r {
if (($2 == REG_HL_IND) && ($4 == REG_HL_IND)) if (($2 == REG_HL_IND) && ($4 == REG_HL_IND))
@@ -1798,7 +1798,7 @@ z80_ld_a : T_Z80_LD reg_r T_COMMA c_ind {
rpn_Free(&$4); rpn_Free(&$4);
} else { } else {
out_AbsByte(0xFA); out_AbsByte(0xFA);
out_RelWord(&$4, true); out_RelWord(&$4, 1);
} }
} else { } else {
error("Destination operand must be A\n"); error("Destination operand must be A\n");
@@ -1809,11 +1809,11 @@ z80_ld_a : T_Z80_LD reg_r T_COMMA c_ind {
z80_ld_ss : T_Z80_LD T_MODE_BC T_COMMA reloc_16bit { z80_ld_ss : T_Z80_LD T_MODE_BC T_COMMA reloc_16bit {
out_AbsByte(0x01 | (REG_BC << 4)); out_AbsByte(0x01 | (REG_BC << 4));
out_RelWord(&$4, true); out_RelWord(&$4, 1);
} }
| T_Z80_LD T_MODE_DE T_COMMA reloc_16bit { | T_Z80_LD T_MODE_DE T_COMMA reloc_16bit {
out_AbsByte(0x01 | (REG_DE << 4)); out_AbsByte(0x01 | (REG_DE << 4));
out_RelWord(&$4, true); out_RelWord(&$4, 1);
} }
/* /*
* HL is taken care of in z80_ld_hl * HL is taken care of in z80_ld_hl
@@ -1826,7 +1826,7 @@ z80_nop : T_Z80_NOP { out_AbsByte(0x00); }
z80_or : T_Z80_OR op_a_n { z80_or : T_Z80_OR op_a_n {
out_AbsByte(0xF6); out_AbsByte(0xF6);
out_RelByte(&$2, true); out_RelByte(&$2, 1);
} }
| T_Z80_OR op_a_r { out_AbsByte(0xB0 | $2); } | T_Z80_OR op_a_r { out_AbsByte(0xB0 | $2); }
; ;
@@ -1890,10 +1890,7 @@ z80_rrca : T_Z80_RRCA { out_AbsByte(0x0F); }
z80_rst : T_Z80_RST reloc_8bit { z80_rst : T_Z80_RST reloc_8bit {
rpn_CheckRST(&$2, &$2); rpn_CheckRST(&$2, &$2);
if (!rpn_isKnown(&$2)) if (!rpn_isKnown(&$2))
// This could be considered as an "operand", but the purpose of the out_RelByte(&$2, 0);
// "operand" flag is to signal to RGBLINK to correct PC,
// which we don't want here.
out_RelByte(&$2, false);
else else
out_AbsByte(0xC7 | $2.nVal); out_AbsByte(0xC7 | $2.nVal);
rpn_Free(&$2); rpn_Free(&$2);
@@ -1902,7 +1899,7 @@ z80_rst : T_Z80_RST reloc_8bit {
z80_sbc : T_Z80_SBC op_a_n { z80_sbc : T_Z80_SBC op_a_n {
out_AbsByte(0xDE); out_AbsByte(0xDE);
out_RelByte(&$2, true); out_RelByte(&$2, 1);
} }
| T_Z80_SBC op_a_r { out_AbsByte(0x98 | $2); } | T_Z80_SBC op_a_r { out_AbsByte(0x98 | $2); }
; ;
@@ -1940,13 +1937,13 @@ z80_stop : T_Z80_STOP {
} }
| T_Z80_STOP reloc_8bit { | T_Z80_STOP reloc_8bit {
out_AbsByte(0x10); out_AbsByte(0x10);
out_RelByte(&$2, true); out_RelByte(&$2, 1);
} }
; ;
z80_sub : T_Z80_SUB op_a_n { z80_sub : T_Z80_SUB op_a_n {
out_AbsByte(0xD6); out_AbsByte(0xD6);
out_RelByte(&$2, true); out_RelByte(&$2, 1);
} }
| T_Z80_SUB op_a_r { out_AbsByte(0x90 | $2); | T_Z80_SUB op_a_r { out_AbsByte(0x90 | $2);
} }
@@ -1960,7 +1957,7 @@ z80_swap : T_Z80_SWAP reg_r {
z80_xor : T_Z80_XOR op_a_n { z80_xor : T_Z80_XOR op_a_n {
out_AbsByte(0xEE); out_AbsByte(0xEE);
out_RelByte(&$2, true); out_RelByte(&$2, 1);
} }
| T_Z80_XOR op_a_r { out_AbsByte(0xA8 | $2); } | T_Z80_XOR op_a_r { out_AbsByte(0xA8 | $2); }
; ;

View File

@@ -488,9 +488,10 @@ static inline void writelong(uint32_t b)
writebyte(b >> 24); writebyte(b >> 24);
} }
static inline void createPatch(enum PatchType type, struct Expression const *expr, bool isOperand) static inline void createPatch(enum PatchType type, struct Expression const *expr,
uint32_t pcShift)
{ {
out_CreatePatch(type, expr, sect_GetOutputOffset(), isOperand); out_CreatePatch(type, expr, sect_GetOutputOffset(), pcShift);
} }
void sect_StartUnion(void) void sect_StartUnion(void)
@@ -617,13 +618,13 @@ void out_String(char const *s)
* Output a relocatable byte. Checking will be done to see if it * Output a relocatable byte. Checking will be done to see if it
* is an absolute value in disguise. * is an absolute value in disguise.
*/ */
void out_RelByte(struct Expression *expr, bool isOperand) void out_RelByte(struct Expression *expr, uint32_t pcShift)
{ {
checkcodesection(); checkcodesection();
reserveSpace(1); reserveSpace(1);
if (!rpn_isKnown(expr)) { if (!rpn_isKnown(expr)) {
createPatch(PATCHTYPE_BYTE, expr, isOperand); createPatch(PATCHTYPE_BYTE, expr, pcShift);
writebyte(0); writebyte(0);
} else { } else {
writebyte(expr->nVal); writebyte(expr->nVal);
@@ -640,9 +641,9 @@ void out_RelBytes(struct Expression *expr, uint32_t n)
checkcodesection(); checkcodesection();
reserveSpace(n); reserveSpace(n);
while (n--) { for (uint32_t i = 0; i < n; i++) {
if (!rpn_isKnown(expr)) { if (!rpn_isKnown(expr)) {
createPatch(PATCHTYPE_BYTE, expr, false); createPatch(PATCHTYPE_BYTE, expr, i);
writebyte(0); writebyte(0);
} else { } else {
writebyte(expr->nVal); writebyte(expr->nVal);
@@ -655,13 +656,13 @@ void out_RelBytes(struct Expression *expr, uint32_t n)
* Output a relocatable word. Checking will be done to see if * Output a relocatable word. Checking will be done to see if
* it's an absolute value in disguise. * it's an absolute value in disguise.
*/ */
void out_RelWord(struct Expression *expr, bool isOperand) void out_RelWord(struct Expression *expr, uint32_t pcShift)
{ {
checkcodesection(); checkcodesection();
reserveSpace(2); reserveSpace(2);
if (!rpn_isKnown(expr)) { if (!rpn_isKnown(expr)) {
createPatch(PATCHTYPE_WORD, expr, isOperand); createPatch(PATCHTYPE_WORD, expr, pcShift);
writeword(0); writeword(0);
} else { } else {
writeword(expr->nVal); writeword(expr->nVal);
@@ -673,13 +674,13 @@ void out_RelWord(struct Expression *expr, bool isOperand)
* Output a relocatable longword. Checking will be done to see if * Output a relocatable longword. Checking will be done to see if
* is an absolute value in disguise. * is an absolute value in disguise.
*/ */
void out_RelLong(struct Expression *expr, bool isOperand) void out_RelLong(struct Expression *expr, uint32_t pcShift)
{ {
checkcodesection(); checkcodesection();
reserveSpace(2); reserveSpace(2);
if (!rpn_isKnown(expr)) { if (!rpn_isKnown(expr)) {
createPatch(PATCHTYPE_LONG, expr, isOperand); createPatch(PATCHTYPE_LONG, expr, pcShift);
writelong(0); writelong(0);
} else { } else {
writelong(expr->nVal); writelong(expr->nVal);
@@ -691,14 +692,14 @@ void out_RelLong(struct Expression *expr, bool isOperand)
* Output a PC-relative relocatable byte. Checking will be done to see if it * Output a PC-relative relocatable byte. Checking will be done to see if it
* is an absolute value in disguise. * is an absolute value in disguise.
*/ */
void out_PCRelByte(struct Expression *expr, bool isOperand) void out_PCRelByte(struct Expression *expr, uint32_t pcShift)
{ {
checkcodesection(); checkcodesection();
reserveSpace(1); reserveSpace(1);
struct Symbol const *pc = sym_GetPC(); struct Symbol const *pc = sym_GetPC();
if (!rpn_IsDiffConstant(expr, pc)) { if (!rpn_IsDiffConstant(expr, pc)) {
createPatch(PATCHTYPE_JR, expr, isOperand); createPatch(PATCHTYPE_JR, expr, pcShift);
writebyte(0); writebyte(0);
} else { } else {
struct Symbol const *sym = rpn_SymbolOf(expr); struct Symbol const *sym = rpn_SymbolOf(expr);

View File

@@ -286,8 +286,7 @@ static void readPatch(FILE *file, struct Patch *patch, char const *fileName, cha
tryGetc(type, file, tryGetc(type, file,
"%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s type: %s", "%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s type: %s",
fileName, sectName, i); fileName, sectName, i);
patch->type = type & 0x7F; patch->type = type;
patch->isOperand = type & PATCH_ISOPERAND;
tryReadlong(patch->rpnSize, file, tryReadlong(patch->rpnSize, file,
"%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s RPN size: %s", "%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s RPN size: %s",
fileName, sectName, i); fileName, sectName, i);

View File

@@ -421,10 +421,6 @@ static int32_t computeRPNExpr(struct Patch const *patch,
isError = true; isError = true;
} else { } else {
value = patch->pcOffset + patch->pcSection->org; value = patch->pcOffset + patch->pcSection->org;
// If the patch is an operand, PC is not at the patch's
// location, but at the (opcode) byte right before it
if (patch->isOperand)
value--;
} }
} else { } else {
symbol = getSymbol(fileSymbols, value); symbol = getSymbol(fileSymbols, value);
@@ -520,9 +516,10 @@ static void applyFilePatches(struct Section *section, struct Section *dataSectio
/* `jr` is quite unlike the others... */ /* `jr` is quite unlike the others... */
if (patch->type == PATCHTYPE_JR) { if (patch->type == PATCHTYPE_JR) {
/* Target is relative to the byte *after* the operand */ // Offset is relative to the byte *after* the operand
// PC as operand to `jr` is lower than reference PC by 2
uint16_t address = patch->pcSection->org uint16_t address = patch->pcSection->org
+ patch->pcOffset + 1; + patch->pcOffset + 2;
int16_t jumpOffset = value - address; int16_t jumpOffset = value - address;
if (!isError && (jumpOffset < -128 || jumpOffset > 127)) if (!isError && (jumpOffset < -128 || jumpOffset > 127))

14
test/asm/ds-@.asm Normal file
View File

@@ -0,0 +1,14 @@
SECTION "test fixed", ROM0[0]
FixedStart:
ds 8, (@ - FixedStart) * 2 + zero
ds 8, (@ - FixedStart) * 2 + zero
SECTION "test floating", ROM0
FloatingStart:
ds 8, (@ - FloatingStart) * 2 + zero
ds 8, (@ - FloatingStart) * 2 + zero
SECTION "zero", ROM0[0]
zero:

0
test/asm/ds-@.err Normal file
View File

0
test/asm/ds-@.out Normal file
View File

BIN
test/asm/ds-@.out.bin Normal file

Binary file not shown.