From ecca7a7737df8dff6d56700cdbbef54a10e46043 Mon Sep 17 00:00:00 2001 From: Stephen Heumann Date: Sun, 11 Dec 2022 14:46:38 -0600 Subject: [PATCH] Never make the segment in the root file dynamic. This would previously happen if a segment directive with "dynamic" appeared before the first function in the program. That would cause the resulting program not to work, because the root segment needs to be a static segment at the start of the program, but if it is dynamic it would come after a jump table and a static segment of library code. The root segments are also configured to refer to main or the NDA/CDA entry points using LEXPR records, so that they can be in dynamic segments (not that they necessarily should be). That change is intentionally not done for CDEV/XCMD/NBA, because they use code resources, which do not support dynamic segments, so it is better to force a linker error in these cases. --- CGI.pas | 3 +++ Header.pas | 4 +++- Native.pas | 19 +++++++++++++++++++ ObjOut.pas | 3 ++- Parser.pas | 1 + Symbol.pas | 5 ++--- cc.notes | 2 ++ 7 files changed, 32 insertions(+), 5 deletions(-) diff --git a/CGI.pas b/CGI.pas index c6219f1..731d85a 100644 --- a/CGI.pas +++ b/CGI.pas @@ -340,6 +340,7 @@ var commonSubexpression: boolean; {do common subexpression removal?} currentSegment,defaultSegment: segNameType; {current & default seg names} segmentKind: integer; {kind field of segment (ored with start/data)} + defaultSegmentKind: integer; {default segment kind} debugFlag: boolean; {generate debugger calls?} debugStrFlag: boolean; {gsbug/niftylist debug names?} dataBank: boolean; {save, restore data bank?} @@ -820,6 +821,8 @@ isXCMD := false; codeGeneration := false; {code generation is not turned on yet} currentSegment := ' '; {start with the blank segment} defaultSegment := ' '; +segmentKind := 0; {default to static code segments} +defaultSegmentKind := 0; smallMemoryModel := true; {small memory model} dataBank := false; {don't save/restore data bank} strictVararg := {save/restore caller's stack around vararg} diff --git a/Header.pas b/Header.pas index 7f91c3a..54e8b4f 100644 --- a/Header.pas +++ b/Header.pas @@ -18,7 +18,7 @@ uses CCommon, MM, Scanner, Symbol, CGI; {$segment 'HEADER'} const - symFileVersion = 36; {version number of .sym file format} + symFileVersion = 37; {version number of .sym file format} var inhibitHeader: boolean; {should .sym includes be blocked?} @@ -887,6 +887,7 @@ procedure EndInclude {chPtr: ptr}; WriteByte(currentSegment[i]); end; {for} WriteWord(segmentKind); + WriteWord(defaultSegmentKind); end; p_unix: WriteByte(ord(unix_1)); @@ -1563,6 +1564,7 @@ var currentSegment[i] := chr(ReadByte); end; {for} segmentKind := ReadWord; + defaultSegmentKind := ReadWord; end; p_unix: unix_1 := boolean(ReadByte); diff --git a/Native.pas b/Native.pas index 486718c..82abe86 100644 --- a/Native.pas +++ b/Native.pas @@ -2318,11 +2318,17 @@ procedure InitFile {keepName: gsosOutStringPtr; keepFlag: integer; partial: bool { set up the data bank register } + var + lisJSL: boolean; {saved copy of isJSL} + begin {SetDataBank} + lisJSL := isJSL; + isJSL := false; CnOut(m_pea); RefName(@'~GLOBALS', 0, 2, -8); CnOut(m_plb); CnOut(m_plb); + isJSL := lisJSL; end; {SetDataBank} @@ -2332,6 +2338,12 @@ procedure InitFile {keepName: gsosOutStringPtr; keepFlag: integer; partial: bool fname2.theString.size := length(fname2.theString.theString); OpenObj(fname2); + {force this to be a static segment} + if (segmentKind & $8000) <> 0 then begin + currentSegment := ' '; + segmentKind := 0; + end; {if} + {write the header} InitNative; Header(@'~_ROOT', $4000, 0); @@ -2353,6 +2365,7 @@ procedure InitFile {keepName: gsosOutStringPtr; keepFlag: integer; partial: bool CnOut(0); {glue code for calling open routine} + isJSL := true; CnOut(m_phb); SetDataBank; CnOut(m_jsl); @@ -2393,6 +2406,7 @@ procedure InitFile {keepName: gsosOutStringPtr; keepFlag: integer; partial: bool RefName(initName, 0, 3, 0); CnOut(m_plb); CnOut(m_rtl); + isJSL := false; end {classic desk accessory initialization} @@ -2410,6 +2424,7 @@ procedure InitFile {keepName: gsosOutStringPtr; keepFlag: integer; partial: bool RefName(lab, menuLen + dispToCDAClose, 4, 0); {glue code for calling open routine} + isJSL := true; CnOut(m_pea); CnOut2(1); CnOut(m_jsl); @@ -2436,6 +2451,7 @@ procedure InitFile {keepName: gsosOutStringPtr; keepFlag: integer; partial: bool RefName(@'~DAID', 0, 3, 0); CnOut(m_plb); CnOut(m_rtl); + isJSL := false; end {control panel device initialization} @@ -2493,6 +2509,7 @@ procedure InitFile {keepName: gsosOutStringPtr; keepFlag: integer; partial: bool else begin {write the initial JSL} + isJSL := true; CnOut(m_jsl); if rtl then RefName(@'~_BWSTARTUP4', 0, 3, 0) @@ -2515,6 +2532,7 @@ procedure InitFile {keepName: gsosOutStringPtr; keepFlag: integer; partial: bool RefName(@'~C_SHUTDOWN2', 0, 3, 0) else RefName(@'~C_SHUTDOWN', 0, 3, 0); + isJSL := false; end; {finish the current segment} @@ -2529,6 +2547,7 @@ procedure InitFile {keepName: gsosOutStringPtr; keepFlag: integer; partial: bool begin {SetStack} if stackSize <> 0 then begin currentSegment := '~_STACK '; {write the header} + segmentKind := 0; Header(@'~_STACK', $4012, 0); Out($F1); {write the DS record to reserve space} Out2(stackSize); diff --git a/ObjOut.pas b/ObjOut.pas index 764735c..6fe174d 100644 --- a/ObjOut.pas +++ b/ObjOut.pas @@ -464,7 +464,8 @@ longPtr^ := segDisp; objLen := objLen + segDisp; {update the length of the obj file} objPtr := pointer(ord4(objHandle^)+objLen); {set objPtr} segDisp := 0; -currentSegment := defaultSegment; {revert to default segment name} +currentSegment := defaultSegment; {revert to default segment name & kind} +segmentKind := defaultSegmentKind; end; {CloseSeg} diff --git a/Parser.pas b/Parser.pas index 7025352..1ce9462 100644 --- a/Parser.pas +++ b/Parser.pas @@ -3701,6 +3701,7 @@ var end {if} else segmentKind := 0; + defaultSegmentKind := segmentKind; Match(semicolonch,22); end {if} else begin diff --git a/Symbol.pas b/Symbol.pas index ab69c14..d30a9af 100644 --- a/Symbol.pas +++ b/Symbol.pas @@ -933,6 +933,7 @@ procedure DoGlobals; currentSegment := ' ' else currentSegment := '~ARRAYS '; + segmentKind := 0; {this segment is not dynamic!} Gen2Name(dc_str, $4000, 1, @'~ARRAYS'); didOne := true; end; {if} @@ -1046,14 +1047,12 @@ begin {DoGlobals} {if printSymbols then {debug} { PrintTable(globalTable); {debug} -{these segments are not dynamic!} -segmentKind := 0; - {declare the ~globals segment, which holds non-array data types} if smallMemoryModel then currentSegment := ' ' else currentSegment := '~GLOBALS '; +segmentKind := 0; {this segment is not dynamic!} Gen2Name(dc_str, $4000, 0, @'~GLOBALS'); GenGlobals; Gen0(dc_enp); diff --git a/cc.notes b/cc.notes index 80412a5..6782303 100644 --- a/cc.notes +++ b/cc.notes @@ -2055,6 +2055,8 @@ int foo(int[42]); 227. If an unsigned 16-bit value was divided by a constant 1000 or larger, and the result was assigned to two different variables (e.g. a = b = c/1000), incorrect code would be generated when using native code peephole optimization. (This was a regression introduced in ORCA/C 2.2.0 B6.) +228. If a segment directive specifying a dynamic segment was used before the first function in the main source file, an invalid .root file would be generated, causing the resulting program to crash. (Note that having your program's main function in a dynamic segment serves little purpose and will cause an unrecoverable error if there is not enough free memory to load it. Also, CDevs, XCMDs, and NBAs cannot use dynamic segments.) + -- Bugs from C 2.1.0 that have been fixed ----------------------------------- 1. In some situations, fread() reread the first 1K or so of the file.