SEGMENT ASSUME
EXAMPLE LOADER
Figure 11-6 shows an example of a loader that reads the iAPX 286 OMF, resolves references to operating-system primitives, and calls kernel procedures to create a new task. In the interest of simplic-ity, this .example t:ecogniz~~ only the single-task OMF produced by the Binder, and all error checking is omitted .. , .. . ..!:,;; . ' . . '
This loader calls the kernel procedures CREATILLDT, LOAD_LDT, LOAD_LDT_GATE, CREATE_TASK, RESERVE~LOTS,arid CHANGE_AR, which are not shown. CREATE_LDT allocates an LDT segment for a new task and installs its descriptors in two of the four GDT slots SPecified by Tt\SK.:.SEL. LOAD_LDT transfers a descriptor from the LDT of the loader to the LDT of the new task. LOAD_LDT_GATE places a gate in the LDT oUhe new task. CREATE_TASK
11-12 121960-001
inter
BINDING AND LOADINGsystem-ID iAPX286 SYSTEM BUILDER, Vx.y INPUT FILES: :F1:NUC.LNK
OUTPUT FILE: (none)
CONTROLS SPECIFIED: TITLE(Gates for Load-Time Binding) NOBOOTLOAD NOOBJECT BUILDFILE(:F1:XOSGAT.BLD) PRINT(:F1:XOSGAT.MP2)
BUILD FILE: :F1:XOSGAT.BLD 1 XQ -RELINQUISH_SLOTS (ENTRY=RELINQUISH -SLOTS, DPL=3,
XQ_ALLOCATE (ENTRY=ALLOCATE, DPL=3,
XQ FREE SEG (ENTRY=FREE SEG, DPL=3, XQ -CREATE ALIAS (ENTRY=CREATE ALIAS, - DPL=3, XQ -CHANGE-AR - (ENTRY=CHANGE AR, DPL=3, WAIT SEMAPHORE (ENTRY=WAIT SEMAPHORE, DPL=3, XQ
-XQ -SIGNAL SEMAPHORE (ENTRY=SIGNAL SEMAPHORE, DPL=3, XQ -SEND MESSAGE (ENTRY=SEND MESSAGE, DPL=3,
GOT (ENTRY=(NUCLEUS_CODE, NUCLEUS_DATA, NUCLEUS.STACK)), DUMMY (ENTRY=(
EXPORT #:F1:XOSGAT.LB2 (KERNEL XQ RESERVE SLOTS,
BUILD FILE PROCESSING COMPLETED
Figure 11-4. Specifying Dummy Gate Exports
PRESENT) ,
BINDING AND LOADING
BINDING LOADER
TASK BOUND TO OPERATING
SYSTEM
Figure 11-5. Strategy for Load-Time Binding
121960-55
finishes creation of the new task by creating a TSS from a template in the loader and placing the new task in the scheduler's queues. RESERVE_SLOTS uses techniques such as those illustrated in Chapter 2 to allocate descriptor table slots. CHANGE~R is used to place the correct type code into the writable data-segment descriptor used by the loader to fill a segment.
The module BOND (shown in figure 11-7) shows the handling of the table of actual gates for operat-ing-system primitives. The procedureGET_LOAD_FILE is not defined here. It simply fetches the file specification for a load able module from, for example, the console or the command line interpreter.
11-14 121960-001
BINDING AND LOADING
PL/M-2B6 COMPILER 960-515 date PAGE 1
system-ID PL/M-286 vx.y COMPILATION OF MODULE LOADER OBJECT MODULE PLACED IN :Fl:LOADER.OBJ
COMPILER INVOKED BY: PLM286.86 :Fl:LOADER.PLM DEBUG
1
$ PAGEWIDTH(71) TITLE('960-S1S')
$ INCLUDE (:Fl:NUCSUB.PLM)
$ NOLIST
$ INCLUDE (:Fl:UDISUB.PLM)
$ NOLIST CONNECTION LITERALLY 'TOKEN' , OFFSET LITERALLY 'WORD' , FOREVER LITERALLY 'WHILE TRUE';
/*******************************************************/
1* Externals *1
RESERVE SLOTS: PROCEDURE(TABLE,COUNT,SLOT_PTR,EXCEP_PT~)
EXTERNAL;
DECLARE TABLE WORD, COUNT WORD, (SLOT_PTR, EXCEP_PTR) POINTER;
END RESERVE_SLOTS;
CHANGE AR: PROCEDURE (SLOT,RIGHTS,EXCEP PTR) EXTERNAL;
DECLARE SLOT SELECTOR, RIGHTS BYTE, EXCEP PTR POINTER;
END CHANGE_AR;
-ALLOCATE: PROCEDURE (SLOT,RIGHTS,SIZE,EXCEP_PTR) EXTERNAL;
-CREATE LDT: PROCEDURE(TASK SEL,srZE,EXCEP PTR) EXTERNAL;
DECLARE TASK SEL SELECTOR; SIZE WORD, EXCEP PTR POINTER;
-Figure 11-6. Binding Loader
BINDING AND LOADING
CREATE TASK: PROCEDURE (TASK SEL, TEMPLATE, PRIORITY, EXCEP PTR) EXTERNAL;
-DECLARE TASK SEL SELECTOR, (TEMPLATE, EXCEP_PTR) POINTER, PRIORITY BYTE;
END CREATE_TASK;
GET LOAD FILE: PROCEDURE (FILE SPEC PTR) EXTERNAL;
DECLARE-FILE SPEC PTR POINTER; -END GET_LOAD=FILE;
BUILD BOND TABLE: PROCEDURE (FILESPEC_PTR, EXCEP_PTR) EXTERNAL;
INITIALIZE SYSTEM: PROCEDURE EXTERNAL;
END INITIALIZE_SYSTEM;
REPORT: PROCEDURE (EXCEP PTR) EXTERNAL;
DECLARE EXCEP PTR POINTER;
END REPORT; -DQ$ATTACH:
PROCEDURE (PATH$P, EXCEP$P) CONNECTION EXTERNAL;
DECLARE (PATH$P, EXCEP$P) POINTER;
END DQ$ATTACH;
DQ$DETACH: PROCEDURE (CONN, EXCEP$P) EXTERNAL;
DECLARE CONN CONNECTION, EXCEP$P PO INTER;
END DQ$DETACH;
ACCESS, NUM$BUF, EXCEP$P) EXTERNAL;
CONNECTION, (ACCESS, NUM$BUF) BYTE, POINTER;
DQ$SEEK: PROCEDURE
(CONN, MODE, LOCATION, EXCEP$P) EXTERNAL;
DECLARE CONN CONNEC~ION, MODE BYTE, LOCATION DWORD, EXCEP$P POINTER;
END DQ$SEEK;
Figur~ 11-6. Binding Loader (Cont'd.)
11-16
2
121960-001
BINDING AND LOADI.NG
DECLARE CONN CONNECTION, COUNT WORD, (BUF$P, EXCEP$P) POINTER;
END DQ$READ;
DQ$CLOSE: PROCEDURE (CONN, EXCEP$P) EXTERNAL;
DECLARE CONN CONNECTION, EXCEP$P POINTER;
END DQ$CLOSE;
DEFAULT PRIORITY LITERALLY '4', ALLOCATED LITERALLY'80H',
OK LITERALLY'0',
EXCEPTION LITERALLY 'EXCEP<>OK';
DECLARE PATH NAME
DECLARE MODULE HEADER STRUCTURE
TOTAL-SPACE DWORD,
Figure 11-6. Binding Loader (Cont'd.)
BINDING AND LOADING
DECLARE DESNAM SEL SELECTOR,
DESNAM-WIDTH LITERALLY '41',
DESNAM-BASED DESNAM SEL (2) STRUCTURE ( NAME (DESNAM WIDTH) BYTE ) , DIX WORD; /* Index */
/* RAM copy of DESCRP section of OMF */
DECLARE DESCRP SEL SELECTOR,
SEGDT BASED DESCRP SEL (2 ) STRUCTURE
SECTION SIZE: PROCEDURE (TOCIX) DWORD;
DECLARE TOCIX WORD; /* Index into Table of contents */
DECLARE TOC(8) DWORD AT (@MODULE_HEADER.DESCRP_LOC), IX WORD;
/* Find the size of an OMF section */
DO IX=TOCIX+l TO 7;
IF TOC(IX)<>0 /* Skip by null sections */
THEN RETURN TOC(IX)-TOC(TOCIX);
END;
END SECTION_SIZE;
/****************************,***************************/
BUILD_DESNAM_TABLE: PROCEDURE (DESNAM_SIZE);
DECLARE DESNAM_SIZE DWORD;
Figure 11-6. Binding Loader (Cont'd.)
11-18 121960·001
BINDING AND LOADING
CALL MOVB(@DESNAM(DIX) .NAME(0),
@DESNAM(DIX) .NAME(l) ,DESNAM_WIDTH-l);
END;
DESNAM USED=DESNAM USED+ACTUAL;
DIX=DESNAM HEADER.DESCR IN-I;
DESNAM(DIX).NAME(0)=DESNAM HEADER. NAME LENGTH;
/* Read rest of name into-table entry-*/
ACTUAL=DQ$READ(LOAD FILE,@DESNAM(DIX) .NAME(l), - DESNAM(DIX) .NAME(0), @EXCEP);
IF EXCEPTION THEN CALL REPORT (@EXCEP);
DESNAM USED=DESNAM USED+ACTUAL;
END /* DO LOOP */;
-/*******************************************************/
LOAD_SEGMENTS: PROCEDURE(LODTXT_SIZE);
DECLARE LODTXT SIZE DECLARE LODTXT HEADER
LOAD OFFSET
DO WHILE LODTXT_USED<LODTXT_SIZE;
Figure 11-6. Binding Loader (Cont'd.)
BINDING AND LOADING
ACTUAL=DQ$READ(LOAD FILE,@LODTXT HEADER,6,@EXCEP);
IF EXCEPTION THEN CALL REPORT (@EXCEP);
LODTXT USED=LODTXT USED+ACTUAL;
IF LODTXT_HEADER.DESCR_IN=TSS_IN
THEN DO; /* Load the Task State Segment */
ACTUAL=DQ$READ(LOAD FILE,@TSS,LODTXT HEADER. LENGTH,
@EXCEP);
-. ,IF EXCEPTION THEN CALL REPORT (@EXCEP);
LODTXT USED=LODTXT USED+ACTUAL;
END /* loading Task-State Segment */;
ELSE DO; /* Load a data or code segment */
LIX=LODTXT HEADER.DESCR IN-I;
IF (SEGDT(LIX) .RIGHTS AND r.J6H) =06H
BUILD$PTR(DCS SEL,LODTXT HEADER. LOAD OFFSET), LODTXT HEADER. LENGTH, @EXCEP);
IF EXCEPTION THEN CALL REPORT (@EXCEP);
LODTXT USED=LODTXT USED+ACTUAL;
/* Put actual access rights in descriptor */
IF EXCEPTION THEN CALL REPORT(@EXCEP);-/* Mark descriptor as allocated */
8*MODULE HEADER.DESCR COUNT, @EXCEP);
IF EXCEPTION THEN CALL REPORT (@EXCEP);
/* Step thru all descriptors */
DO LIX = '" TO MODULE HEADER.DESCR COUNT-I;
/* Read LDT entry */ -ACTUAL=DQ$READ (LOAD FILE, @SEGDT(LIX),
- 8, @EXCEP);
Figure 11-6. Binding Loader (Cont'd.)
11-20 121960-001