MPW Embedding

One of our primary goals was to take advantage of the Oberon language in mixed language projects. As outlined above, this can be achieved on a Macintosh through MPW compatibility. The added benefit of MPW embedding is the availability of the standard MPW source-level debugger, SADE. The pertinent extensions to the Project Oberon compiler fall in two areas, object file format and symbol files for SADE.

The MPW linker is capable of combining code fragments from every MPW compiler (e.g. FORTRAN, Pascal, Modula-2, C, C++, and many more) into Macintosh code segments [Apple1]. Furthermore it generates the above mentioned jump tables, and adds resources into the executable (applications, system extension, drivers, desk accessories, etc.).

The linker makes a particularly important Oberon feature hard to implement however, the dynamic type checks [Wirth3]. Tags identify the type of a dynamic variable and communicate their structure to the garbage collector. Similar to user types, they are arranged in a tree like fashion, where each type tag holds references to predecessors. These references are generated symbolically by the compiler and transformed into addresses when the program is loaded.

Macintosh code is organized in segments which are loaded automatically when they are needed. A program is able to purge segments when it decides that the code in a particular segment is no longer needed [Apple3]. An MPW compiler doesn't make the final decision about segmentation. Segments are ultimately built by the linker. Therefore the compiler cannot guarantee that every reference in a defining module is available when a segment is loaded. In the case of MPW Oberon, the effect is that the tag addresses cannot be entered into every reference during program initialization. Some segments with tag references might be loaded at a later time. The linker doesn't include information on type and position of references into the application either.

MacOberon chose to adapt the type tag hierarchy when it loads a module with the special loader application [Franz]. A type tag is referenced as a global variable and the respective address is entered at all pertinent locations. The loader has to fix every reference within type tags and every access operation in the defining module. Furthermore it substitutes addresses in importing modules as if they were global variables.

MPW Oberon has to rely on the standard Macintosh segment loader, i.e. it needs a static (compile time) solution for the problem. MPW Oberon uses a trick in order to enable the linker to make the necessary connections: it treats each type tag as a procedure, turning references to tags into procedure calls. Type tags are kept in a special code segment together with their initialization procedure. This tag segment is loaded as soon as the main initialization calls the tag initialization procedure. The latter transforms the jump-instructions together with the relative addresses in the tag-segment into absolute addresses which remain constant during the execution of the program (figure 4). Access to type tags from true code uses the segment table, which is adjusted properly by the segment loader.


Figure 4: Segment table entry

MPW Oberon and the MPW Object File Architecture

The basic concept of MPW object files are modules containing either code (procedures) or global data (variables). In the object file, each module is described by means of a module record with information about type, size, and name of the module. The module itself is held in the content record. Modules for global data contain real data in the case of programming languages supporting static data initialization (e.g. C). Besides module and content records, object files store other recordtypes to supply the linker with control information, for example the first record specifying the presence of symbol tables for the debugger.

The PO compiler was extended accordingly to fill its output into object file records. MPW Oberon creates an object file for every Oberon module with at least one content record. There is only one content record for each procedure, limiting the size of a procedure to 64 KByte. The linker resolves references based on names. For every reference to global variables or calls to other procedures, there will be reference records with the name of the referenced object and the position of the reference (see figure 5). Reference records actually contain unique numbers instead of strings. These numbers are associated with the module names (strings) by means of a dictionary record. MPW Oberon creates this record right after the first record.


Figure 5: Source code and object file

Debugging and SADE

The aforementioned record types are sufficient to build an executable. More information is however needed to support symbolic, source-level debugging during runtime. SADE needs information about static nesting, correlation between source and object code, structure of global data and the stackframe, as well as data types. The following record types convey this information:
Previous Section, Next Section, Contents