Avoid out-of-range branches around asm code using dcl directives.

The branch range calculation treated dcl directives as taking 2 bytes rather than 4, which could result in out-of-range branches. These could result in linker errors (for forward branches) or silently generating wrong code (for backward branches).

This patch now treats dcb, dcw, and dcl as separate directives in the native-code layer, so the appropriate length can be calculated for each.

Here is an example of code affected by this:

int main(int argc, char **argv) {
top:
        if (!argc) { /* this caused a linker error */
                asm {
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                }
                goto top; /* this generated bad code with no error */
        }
}
This commit is contained in:
Stephen Heumann 2022-10-13 18:00:16 -05:00
parent 19683706cc
commit 99a10590b1
5 changed files with 23 additions and 13 deletions

17
Asm.pas
View File

@ -568,13 +568,18 @@ while not (token.kind in [rbracech,eofsy]) do begin
{handle data declarations} {handle data declarations}
else if opc <= o_dcl then begin else if opc <= o_dcl then begin
Exp([semicolonch], true); Exp([semicolonch], true);
code^.s := d_add; if opc = o_dcb then begin
if opc = o_dcb then code^.s := d_dcb;
code^.r := ord(direct) code^.r := ord(direct);
else if opc = o_dcw then end {if}
code^.r := ord(absolute) else if opc = o_dcw then begin
else code^.s := d_dcw;
code^.r := ord(absolute);
end {else if}
else begin
code^.s := d_dcl;
code^.r := ord(longabsolute); code^.r := ord(longabsolute);
end; {else}
end {if opc <= o_dcl} end {if opc <= o_dcl}
{handle the brk instruction} {handle the brk instruction}

View File

@ -205,8 +205,11 @@ const
d_wrd = 261; d_wrd = 261;
d_sym = 262; d_sym = 262;
d_cns = 263; d_cns = 263;
d_dcb = 264;
d_dcw = 265;
d_dcl = 266;
max_opcode = 263; max_opcode = 266;
asmFlag = $8000; {or'd with opcode to indicate asm code} asmFlag = $8000; {or'd with opcode to indicate asm code}

View File

@ -164,5 +164,5 @@ size dc i1'2,2,2,2,2,2,2,2,1,3,1,1,3,3,3,4'
dc i1'3,2,2,2,2,2,2,2,1,3,1,1,3,3,3,4' dc i1'3,2,2,2,2,2,2,2,1,3,1,1,3,3,3,4'
dc i1'2,2,2,2,3,2,2,2,1,3,1,1,3,3,3,4' dc i1'2,2,2,2,3,2,2,2,1,3,1,1,3,3,3,4'
dc i1'0,0,1,2,0,2,0,255' dc i1'0,0,1,2,0,2,0,255,1,2,4'
end end

View File

@ -545,7 +545,7 @@ case mode of
end; end;
longabsolute: begin longabsolute: begin
if opcode <> d_add then begin if opcode <> d_dcl then begin
CnOut(opcode); CnOut(opcode);
i := 3; i := 3;
end {if} end {if}
@ -556,7 +556,7 @@ case mode of
else if (flags & constantOpnd) <> 0 then begin else if (flags & constantOpnd) <> 0 then begin
lval := ord4(name); lval := ord4(name);
CnOut2(long(lval).lsw); CnOut2(long(lval).lsw);
if opcode = d_add then if opcode = d_dcl then
CnOut2(long(lval).msw) CnOut2(long(lval).msw)
else else
CnOut(long(lval).msw); CnOut(long(lval).msw);
@ -566,13 +566,13 @@ case mode of
else begin else begin
CnOut2(operand); CnOut2(operand);
CnOut(0); CnOut(0);
if opcode = d_add then if opcode = d_dcl then
CnOut(0); CnOut(0);
end; {else} end; {else}
end; end;
absolute: begin absolute: begin
if opcode <> d_add then if opcode <> d_dcw then
CnOut(opcode); CnOut(opcode);
if (flags & localLab) <> 0 then if (flags & localLab) <> 0 then
LabelSearch(long(name).lsw, 2, 0, operand) LabelSearch(long(name).lsw, 2, 0, operand)
@ -585,7 +585,7 @@ case mode of
end; end;
direct: begin direct: begin
if opcode <> d_add then if opcode <> d_dcb then
CnOut(opcode); CnOut(opcode);
if (flags & localLab) <> 0 then if (flags & localLab) <> 0 then
LabelSearch(long(name).lsw, 1, 0, operand) LabelSearch(long(name).lsw, 1, 0, operand)

View File

@ -1907,6 +1907,8 @@ int foo(int[42]);
(Dave Tribby) (Dave Tribby)
209. The native code peephole optimizer might not correctly analyze whether short branch instructions can be used around an asm statement with one or more dcl directives. This could cause "Relative address out of range" linker errors in some cases, or generate bad code without reporting any errors in others.
-- Bugs from C 2.1.0 that have been fixed ----------------------------------- -- Bugs from C 2.1.0 that have been fixed -----------------------------------
1. In some situations, fread() reread the first 1K or so of the file. 1. In some situations, fread() reread the first 1K or so of the file.