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}
else if opc <= o_dcl then begin
Exp([semicolonch], true);
code^.s := d_add;
if opc = o_dcb then
code^.r := ord(direct)
else if opc = o_dcw then
code^.r := ord(absolute)
else
if opc = o_dcb then begin
code^.s := d_dcb;
code^.r := ord(direct);
end {if}
else if opc = o_dcw then begin
code^.s := d_dcw;
code^.r := ord(absolute);
end {else if}
else begin
code^.s := d_dcl;
code^.r := ord(longabsolute);
end; {else}
end {if opc <= o_dcl}
{handle the brk instruction}

View File

@ -205,8 +205,11 @@ const
d_wrd = 261;
d_sym = 262;
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}

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'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

View File

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

View File

@ -1907,6 +1907,8 @@ int foo(int[42]);
(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 -----------------------------------
1. In some situations, fread() reread the first 1K or so of the file.