******************************** RELOCATABLE OBJECT MODULE FORMAT ******************************** Revision Date: 5/92 No Disk Included The following information applies to to the Microsoft products listed below. -------------------------------------------------------------------- | INFORMATION PROVIDED IN THIS DOCUMENT AND ANY SOFTWARE THAT MAY | | ACCOMPANY THIS DOCUMENT (collectively referred to as an | | Application Note) IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY | | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO | | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A | | PARTICULAR PURPOSE. The user assumes the entire risk as to the | | accuracy and the use of this Application Note. This Application | | Note may be copied and distributed subject to the following | | conditions: 1) All text must be copied without modification and | | all pages must be included; 2) If software is included, all files | | on the disk(s) must be copied without modification [the MS-DOS(R) | | utility DISKCOPY is appropriate for this purpose]; 3) All | | components of this Application Note must be distributed together; | | and 4) This Application Note may not be distributed for profit. | | | | Copyright 1992 Microsoft Corporation. All Rights Reserved. | | Microsoft, MS-DOS, QuickC, and QuickPascal are registered | | trademarks and Windows, QuickBasic, and Visual Basic are | | trademarks of Microsoft Corporation. | | | -------------------------------------------------------------------- APPLICABLE PRODUCTS =================== This application note applies to all versions of the following Microsoft language products: Microsoft Basic Microsoft C Microsoft C++ Microsoft COBOL Microsoft FORTRAN Microsoft Macro Assembler (MASM) Microsoft Pascal Microsoft QuickBasic(TM) Microsoft QuickC(C) Microsoft QuickC for Windows(TM) Microsoft QuickPascal(C) Microsoft Visual Basic(TM) TABLE OF CONTENTS ================== Section ------- Introduction 1 The Object Record Format 1 Frequent Object Record Subfields 1 Order of Records 1 Record Specifics 1 80H THEADR--Translator Header Record 1 82H LHEADR--Library Module Header Record 2 88H COMENT--Comment Record 2 88H IMPDEF--Import Definition Record (Comment Class A0, Subtype 01) 2 88H EXPDEF--Export Definition Record (Comment Class A0, Subtype 02) 2 88H INCDEF--Incremental Compilation Record (Cmnt Class A0, Sub 03) 2 88H LNKDIR--C++ Directives Record (Comment Class A0, Subtype 05) 2 88H LIBMOD--Library Module Name Record (Comment Class A3) 2 88H EXESTR--Executable String Record (Comment Class A4) 2 88H INCERR--Incremental Compilation Error (Comment Class A6) 2 88H NOPAD--No Segment Padding (Comment Class A7) 2 88H WKEXT--Weak Extern Record (Comment Class A8) 2 88H LZEXT--Lazy Extern Record (Comment Class A9) 3 88H PharLap Format Record (Comment Class AA) 3 8AH or 8BH MODEND--Module End Record 3 8CH EXTDEF--External Names Definition Record 3 8EH TYPDEF--Type Definition Record 3 90H or 91H PUBDEF--Public Names Definition Record 3 94H or 95H LINNUM--Line Numbers Record 3 96H LNAMES--List of Names Record 4 98H or 99H SEGDEF--Segment Definition Record 4 9AH GRPDEF--Group Definition Record 4 9CH or 9DH FIXUPP--Fixup Record 4 A0H or A1H LEDATA--Logical Enumerated Data Record 5 A2H or A3H LIDATA--Logical Iterated Data Record 5 B0H COMDEF--Communal Names Definition Record 5 B2H or B3H BAKPAT--Backpatch Record 5 B4H or B5H LEXTDEF--Local External Names Definition Record 5 B6H or B7H LPUBDEF--Local Public Names Definition Record 5 B8H LCOMDEF--Local Communal Names Definition Record 5 BCH CEXTDEF--COMDAT External Names Definition Record 5 C2H or C3H COMDAT--Initialized Communal Data Record 5 C4H or C5H LINSYM--Symbol Line Numbers Record 6 C6H ALIAS--Alias Definition Record 6 C8H or C9H NBKPAT--Named Backpatch Record 6 CAH LLNAMES--Local Logical Names Definition Record 6 Appendix 1: CodeView Extensions 6 Appendix 2: Microsoft MS-DOS Library Format 6 INTRODUCTION ============ This document is intended to serve a purpose that up until now has been performed by the LINK source code: to be the official definition for the object module format (the information inside .OBJ files) supported by Microsoft's language products. The goal is to include all currently used or obsolete OMF record types, all currently used or obsolete field values, and all extensions made by Microsoft, IBM, and others. The information provided here has been consolidated from many other documents: "The MS-DOS Encyclopedia" by Microsoft Press, an OMF386 document from IBM that was made available by the Joint Development Agreement, the "PharLap 386|Link Reference Manual," the Intel 8086 object module specification (Intel Technical Specification 121748- 001), and internal Microsoft documents. Where there have been conflicts, the current LINK source code has decided which information is correct. The audience for this document is expected to be technical, with background knowledge of the process by which source code is converted into an executable file in the MS-DOS or OS/2 environment. If you need more tutorial information, "The MS-DOS Encyclopedia" is a good place to start. THE OBJECT RECORD FORMAT ======================== Record Format ------------- All object records conform to the following format: <------Record Length in Bytes-----> 1 2 1 Record Record Record Checksum or 0 Type Length Contents The Record Type field is a 1-byte field containing the hexadecimal number that identifies the type of object record. The Record Length field is a 2-byte field that gives the length of the remainder of the object record in bytes (excluding the bytes in the Record Type and Record Length fields). The record length is stored with the low-order byte first. An entire record occupies 3 bytes plus the number of bytes in the Record Length field. The Record Contents field varies in size and format, depending on the record type. The Checksum field is a 1-byte field that contains the negative sum (modulo 256) of all other bytes in the record. In other words, the checksum byte is calculated so that the low-order byte of the sum of all the bytes in the record, including the checksum byte, equals 0. Overflow is ignored. Some compilers write a 0 byte rather than computing the checksum, so either form should be accepted by programs that process object modules. NOTES The maximum size of the entire record (unless otherwise noted for specific record types) is 1024 bytes. For LINK386, the format is determined by the least-significant bit of the Record Type field. An odd Record Type indicates that certain numeric fields within the record contain 32-bit values; an even Record Type indicates that those fields contain 16-bit values. The affected fields are described with each record. Note that this principle does not govern the Use32/Use16 segment attribute (which is set in the ACBP byte of SEGDEF records); it simply specifies the size of certain numeric fields within the record. It is possible to use 16-bit OMF records to generate 32-bit segments, or vice versa. LINK ignores the value of the checksum byte, but some other utilities do not. Microsoft's Quick languages write a 0 byte instead of computing a checksum. FREQUENT OBJECT RECORD SUBFIELDS ================================ The contents of each record are determined by the record type, but certain subfields appear frequently enough to be explained separately. The format of such fields is below. Names ----- A name string is encoded as an 8-bit unsigned count followed by a string of count characters. The character set is usually some ASCII subset. A null name is specified by a single byte of 0 (indicating a string of length 0). Indexed References ------------------ Certain items are ordered by occurrence and are referenced by index. The first occurrence of the item has index number 1. Index fields may contain 0 (indicating that they are not present) or values from 1 through 7FFF. The index number field in an object record can be either 1 or 2 bytes long. If the number is in the range 0-7FH, the high-order bit (bit 7) is 0 and the low-order bits contain the index number, so the field is only 1 byte long. If the index number is in the range 80- 7FFFH, the field is 2 bytes long. The high-order bit of the first byte in the field is set to 1, and the high-order byte of the index number (which must be in the range 0-7FH) fits in the remaining 7 bits. The low-order byte of the index number is specified in the second byte of the field. The code to decode an index is: if (first_byte & 0x80) index_word = (first_byte & 7F) * 0x100 + second_byte; else index_word = first_byte; Type Indexes ------------ Type Index fields occupy 1 or 2 bytes and occur in PUBDEF, LPUBDEF, COMDEF, LCOMDEF, EXTDEF, and LEXTDEF records. They are encoded as described above for indexed references, but the interpretation of the values stored is governed by whether the module has the "new" or "old" object module format. "Old" versions of the OMF (indicated by lack of a COMENT record with comment class A1), have Type Index fields that contain indexes into previously seen TYPDEF records. This format is no longer produced by Microsoft products and is ignored by LINK if it is present. See the section of this document on TYPDEF records for details on how this was used. "New" versions of the OMF (indicated by the presence of a COMENT record with comment class A1), have Type Index fields that contain proprietary CodeView information. For more information on CodeView, see Appendix 1. NOTE: Currently, the linker does not perform type checking. Ordered Collections ------------------- Certain records and record groups are ordered so that the records may be referred to with indexes (the format of indexes is described in the "Indexed References" section of this document). The same format is used whether an index refers to names, logical segments, or other items. The overall ordering is obtained from the order of the records within the file together with the ordering of repeated fields within these records. Such ordered collections are referenced by index, counting from 1 (index 0 indicates unknown or not specified). For example, there may be many LNAMES records within a module, and each of those records may contain many names. The names are indexed starting at 1 for the first name in the first LNAMES record encountered while reading the file, 2 for the second name in the first record, and so forth, with the highest index for the last name in the last LNAMES record encountered. The ordered collections are: Names Ordered by occurrence of LNAMES records and names within each. Referenced as a name index. Logical Ordered by occurrence of SEGDEF records in Segments file. Referenced as a segment index. Groups Ordered by occurrence of GRPDEF records in file. Referenced as a group index. External Ordered by occurrence of EXTDEF, COMDEF, Symbols LEXTDEF, and LCOMDEF records and symbols within each. Referenced as an external name index (in FIXUP subrecords). Numeric 2- and 4-Byte Fields ---------------------------- Words and double words (16- and 32-bit quantities) are stored in Intel byte order (lowest address is least significant). Certain records, notably SEGDEF, PUBDEF, LPUBDEF, LINNUM, LEDATA, LIDATA, FIXUPP, and MODEND, contain size, offset, and displacement values that may be 32-bit quantities for Use32 segments. The encoding is as follows: - When the least-significant bit of the record type byte is set (that is, the record type is an odd number), the numeric fields are 4 bytes. - When the least-significant bit of the record type byte is clear, the fields occupy 2 bytes. The values are zero-extended when applied to Use32 segments. NOTE: See the description of SEGDEF records in this document for an explanation of Use16/Use32 segments. ORDER OF RECORDS ================ The sequence in which the types of object records appear in an object module is fairly flexible in some respects. Several record types are optional, and if the type of information they carry is unnecessary, they are omitted from the object module. In addition, most object record types can occur more than once in the same object module. And because object records are variable in length, it is often possible to choose between combining information into one large record or breaking it down into several smaller records of the same type. An important constraint on the order in which object records appear is the need for some types of object records to refer to information contained in other records. Because the linker processes the records sequentially, object records containing such information must precede the records that refer to the information. For example, two types of object records, SEGDEF and GRPDEF, refer to the names contained in an LNAMES record. Thus, an LNAMES record must appear before any SEGDEF or GRPDEF records that refer to it so that the names in the LNAMES record are known to the linker by the time it processes the SEGDEF or GRPDEF records. The record order is chosen so that linker passes through an object module are minimized. Microsoft LINK makes two passes through the object modules: the first pass may be cut short by the presence of the Link Pass Separator COMENT record; the second pass processes all records. For greatest linking speed, all symbolic information should occur at the start of the object module. This order is recommended but not mandatory. The general ordering is: Identifier Record(s) -------------------- NOTE: This must be the first record. THEADR or LHEADR record Records Processed by LINK Pass 1 -------------------------------- The following records may occur in any order but they must precede the Link Pass Separator if it is present: COMENT records identifying object format and extensions COMENT records other than Link Pass Separator comment LNAMES or LLNAMES records providing ordered name list SEGDEF records providing ordered list of program segments GRPDEF records providing ordered list of logical segments TYPDEF records (obsolete) ALIAS records PUBDEF records locating and naming public symbols LPUBDEF records locating and naming private symbols COMDEF, LCOMDEF, EXTDEF, LEXTDEF, and CEXTDEF records NOTE: This group of records is indexed together, so external name index fields in FIXUPP records may refer to any of the record types listed. Link Pass Separator (Optional) ------------------------------ COMENT class A2 record indicating that Pass 1 of the linker is complete. When this record is encountered, LINK stops reading the object file in Pass 1; no records after this comment are read in Pass 1. All the records listed above must come before this COMENT record. For greater linking speed, all LIDATA, LEDATA, FIXUPP, BAKPAT, INCDEF, and LINNUM records should come after the A2 COMENT record, but this is not required. In LINK, Pass 2 begins again at the start of the object module, so these records are processed in Pass 2 no matter where they are placed in the object module. Records Ignored by LINK Pass 1 and Processed by LINK Pass 2 ----------------------------------------------------------- The following records may come before or after the Link Pass Separator: LIDATA, LEDATA, or COMDAT records followed by applicable FIXUPP records FIXUPP records containing only THREAD subrecords BAKPAT and NBKPAT FIXUPP records COMENT class A0, subrecord type 03 (INCDEF) records containing incremental compilation information for FIXUPP and LINNUM records LINNUM and LINSYM records providing line number and program code or data association Terminator ---------- MODEND record indicating end of module with optional start address RECORD SPECIFICS ================ Details of each record (form and content), together with historical notes and comments on usage, are presented in the sections that follow. Conflicts between various OMFs that overlap in their use of record types or fields are marked. Below is a combined list of record types defined by the Intel 8086 OMF specification and record types added after that specification was finished. Titles in square brackets ([]) indicate record types that have been implemented and that are described in this document. Titles not in square brackets indicate record types that have not been implemented and are followed by a paragraph of description from the Intel specification. For unimplemented record types, a subtle distinction is made between records that LINK ignores and those for which LINK generates an "illegal object format" error condition. Records Currently Defined ------------------------- 6EH RHEADR R-Module Header Record This record serves to identify a module that has been processed (output) by LINK-86/LOCATE-86. It also specifies the module attributes and gives information on memory usage and need. This record type is ignored by Microsoft LINK. 70H REGINT Register Initialization Record This record provides information about the 8086 register/register-pairs: CS and IP, SS and SP, DS and ES. The purpose of this information is for a loader to set the necessary registers for initiation of execution. This record type is ignored by Microsoft LINK. 72H REDATA Relocatable Enumerated Data Record This record provides contiguous data from which a portion of an 8086 memory image may eventually be constructed. The data may be loaded directly by an 8086 loader, with perhaps some base fixups. The record may also be called a Load-Time Locatable (LTL) Enumerated Data Record. This record type is ignored by Microsoft LINK. 74H RIDATA Relocatable Iterated Data Record This record provides contiguous data from which a portion of an 8086 memory image may eventually be constructed. The data may be loaded directly by an 8086 loader, but data bytes within the record may require expansion. The record may also be called a Load-Time Locatable (LTL) Iterated Data Record. This record type is ignored by Microsoft LINK. 76H OVLDEF Overlay Definition Record This record provides the overlay's name, its location in the object file, and its attributes. A loader may use this record to locate the data records of the overlay in the object file. This record type is ignored by Microsoft LINK. 78H ENDREC End Record This record is used to denote the end of a set of records, such as a block or an overlay. This record type is ignored by Microsoft LINK. 7AH BLKDEF Block Definition Record This record provides information about blocks that were defined in the source program input to the translator that produced the module. A BLKDEF record will be generated for every procedure and for every block that contains variables. This information is used to aid debugging programs. This record type is ignored by Microsoft LINK. 7CH BLKEND Block End Record This record, together with the BLKDEF record, provides information about the scope of variables in the source program. Each BLKDEF record must be followed by a BLKEND record. The order of the BLKDEF, debug symbol records, and BLKEND records should reflect the order of declaration in the source module. This record type is ignored by Microsoft LINK. 7EH DEBSYM Debug Symbols Record This record provides information about all local symbols, including stack and based symbols. The purpose of this information is to aid debug- ging programs. This record type is ignored by Microsoft LINK. [80H] [THEADR] [Translator Header Record] [82H] [LHEADR] [Library Module Header Record] 84H PEDATA Physical Enumerated Data Record This record provides contiguous data, from which a portion of an 8086 memory image may be constructed. The data belongs to the "unnamed absolute segment" in that it has been assigned absolute 8086 memory addresses and has been divorced from all logical segment information. This record type is ignored by Microsoft LINK. 86H PIDATA Physical Iterated Data Record This record provides contiguous data, from which a portion of an 8086 memory image may be constructed. It allows initialization of data segments and provides a mechanism to reduce the size of object modules when there is repeated data to be used to initialize a memory image. The data belongs to the "unnamed absolute segment." This record type is ignored by Microsoft LINK. [88H] [COMENT] [Comment Record] [8AH/8BH] [MODEND] [Module End Record] [8CH] [EXTDEF] [External Names Definition Record] [8EH] [TYPDEF] [Type Definition Record] [90H/91H] [PUBDEF] [Public Names Definition Record] 92H LOCSYM Local Symbols Record This record provides information about symbols that were used in the source program input to the translator that produced the module. This information is used to aid debugging programs. This record has a format identical to the PUBDEF record. This record type is ignored by Microsoft LINK. [94H/95H] [LINNUM] [Line Numbers Record] [96H] [LNAMES] [List of Names Record] [98H/99H] [SEGDEF] [Segment Definition Record] [9AH] [GRPDEF] [Group Definition Record] [9CH/9DH] [FIXUPP] [Fixup Record] 9EH (none) Unnamed record This record number was the only even number not defined by the original Intel specification. Apparently it was never used. This record type is ignored by Microsoft LINK. [A0H/A1H] [LEDATA] [Logical Enumerated Data Record] [A2H/A3H] [LIDATA] [Logical Iterated Data Record] A4H LIBHED Library Header Record This record is the first record in a library file. It immediately precedes the modules (if any) in the library. Following the modules are three more records in the following order: LIBNAM, LIBLOC, and LIBDIC. This record type is ignored by Microsoft LINK. A6H LIBNAM Library Module Names Record This record lists the names of all the modules in the library. The names are listed in the same sequence as the modules appear in the library. This record type is ignored by Microsoft LINK. A8H LIBLOC Library Module Locations Record This record provides the relative location, within the library file, of the first byte of the first record (either a THEADR or LHEADR or RHEADR record) of each module in the library. The order of the locations corresponds to the order of the modules in the library. This record type is ignored by Microsoft LINK. AAH LIBDIC Library Dictionary Record This record gives all the names of public symbols within the library. The public names are separated into groups; all names in the nth group are defined in the nth module of the library. This record type is ignored by Microsoft LINK. [B0H] [COMDEF] [Communal Names Definition Record] [B2H/B3H] [BAKPAT] [Backpatch Record] [B4H] [LEXTDEF] [Local External Names Definition Record] [B6H/B7H] [LPUBDEF] [Local Public Names Definition Record] [B8H] [LCOMDEF] [Local Communal Names Definition Record] BAH/BBH COMFIX Communal Fixup Record Microsoft doesn't support this never- implemented IBM extension. This record type generates an error when it is encountered by Microsoft LINK. BCH CEXTDEF COMDAT External Names Definition Record C0H SELDEF Selector Definition Record Microsoft doesn't support this never- implemented IBM extension. This record type generates an error when it is encountered by Microsoft LINK. [C2H/C3] [COMDAT] [Initialized Communal Data Record] [C4H/C5H] [LINSYM] [Symbol Line Numbers Record] [C6H] [ALIAS] [Alias Definition Record] [C8H/C9H] [NBKPAT] [Named Backpatch Record] [CAH] [LLNAMES] [Local Logical Names Definition Record] [F0H] [Library Header Record] Although this is not actually an OMF record type, the presence of a record with F0H as the first byte indicates that the module is a Microsoft library. The format of a library file is given in Appendix 2. [F1H] [Library End Record] 80H THEADR--TRANSLATOR HEADER RECORD ==================================== Description ----------- The THEADR record contains the name of the object module. This name identifies an object module within an object library or in messages produced by the linker. History ------- Unchanged. Record Format ------------- 1 2 1 <-String Length-> 1 80 Record String Name String Checksum Length Length The String Length byte gives the number of characters in the name string; the name string itself is ASCII. This name is usually that of the file that contains a program's source code (if supplied by the language translator), or may be specified directly by the programmer (for example, TITLE pseudo-operand or assembler NAME directive). NOTES The name string is always present; a null name is allowed but not recommended (because it doesn't provide much information for a debugging program). In object modules generated by Microsoft compilers, the name string indicates the full path and filename of the file that contained the source code for the module. This record, or an LHEADR record must occur as the first object record. More than one header record is allowed (as a result of an object bind, or if the source arose from multiple files as a result of include processing). Examples -------- The following THEADR record was generated by the Microsoft C Compiler: 0 1 2 3 4 5 6 7 8 9 A B C D E F 0000 80 09 00 07 68 65 6C 6C 6F 2E 63 CB ...hello.c Byte 00H contains 80H, indicating a THEADR record. Bytes 01-02H contain 0009H, the length of the remainder of the record. Bytes 03-0AH contain the T-module name. Byte 03H contains 07H, the length of the name, and bytes 04H through 0AH contain the name itself (HELLO.C). Byte 0BH contains the Checksum field, 0CBH. 82H LHEADR--LIBRARY MODULE HEADER RECORD ======================================== Description ----------- This record is very similar to the THEADR record. It is used to indicate the name of a module within a library file (which has an internal organization different from that of an object module). History ------- This record type was defined in the original Intel specification with the same format but with a different purpose, so its use for libraries should be considered a Microsoft extension. Record Format ------------- 1 2 1 <-String Length-> 1 82 Record String Name String Checksum Length Length NOTE: In LINK, THEADR, and LHEADR records are handled identically. See Appendix 2 for a complete description of Microsoft's library file format. ********** Document 2 ********** 88H COMENT--COMMENT RECORD ========================== Description ----------- The COMENT record contains a character string that may represent a plain text comment, a symbol meaningful to a program such as LIB or LINK, or even binary-encoded identification data. An object module can contain any number of COMENT records. History ------- New comment classes have been added or changed for LINK386. They are: 9D, A0, A1, A2, A4, AA, B0, and B1. Comment class A2 was added for C version 5.0. Histories for comment classes A0, A3, A4, A6, A7, and A8 are given later in this section. 68000 and big-endian comments were added for C version 7.0. Record Format ------------- The comment records are actually a group of items, classified by comment class. 1 2 1 1 <-Record Length Minus 3-> 1 88 Record Comment Comment Commentary Byte String Checksum Length Type Class (optional) Comment Type ------------ The Comment Type field is bit significant; its layout is <-------1 byte-----------------------------------------------> NP NL 0 0 0 0 0 0 where NP (no purge bit) is set if the comment is to be preserved by utility programs that manipulate object modules. This bit can protect an important comment, such as a copyright message, from deletion. NL (no list bit) is set if the comment is not to be displayed by utility programs that list the contents of object modules. This bit can hide a comment. The remaining bits are unused and should be set to 0. Comment Class and Commentary Byte String ---------------------------------------- The Comment Class field is an 8-bit numeric field that conveys information by its value (accompanied by a null byte string) or indicates the information to be found in the accompanying byte string. The byte string's length is determined from the record length, not by an initial count byte. The values that have been defined (including obsolete values) are the following: 0 Translator Translator; it may name the source language or translator. We recommend that the translator name and version, plus the optimization level used for compilation, be recorded here. Other compiler or assembler options can be included, although current practice seems to be to place these under comment class 9D. 1 Intel Ignored by LINK. Comments of this class copyright are used by QuickC for padding. 2 - 9B Intel The values from 9C through FF are reserved ignored by Intel products. 81 Library Replaced by comment class 9F; contents specifier-- are identical to 9F. obsolete 9C MS-DOS The byte string is then 2 bytes and version-- specifies the MS-DOS version number. obsolete This comment class is not supported by LINK. 9D Memory model- This information is currently generated -ignored by the C compiler for use by the XENIX linker; it is ignored by the MS-DOS and OS/2 versions of LINK. The byte string consists of from one to three ASCII characters and indicates the following: 0, 1, 2, 8086, 80186, 80286, or or 3 80386 instructions generated, respectively O Optimization performed on code s, m, c, Small, medium, compact, l, or h large, or huge model A, B, C, 68000, 68010, 68020, or D 68030 instructions generated, respectively 9E DOSSEG Sets Microsoft LINK's DOSSEG switch. The byte string is null. This record is included in the startup module in each language library. It directs the linker to use the standardized segment ordering, according to the naming conventions documented with MS-DOS, OS/2, and accompanying language products. 9F Default The byte string contains a library library filename (without a lead count byte and search name without an extension), which is searched in order to resolve external references within the object module. The default library search can be overridden with LINK's /NODEFAULTLIBRARYSEARCH switch. A0 OMF This class consists of a set of extensions records, identified by subtype (first byte of commentary string). Values supported by LINK are: 01 IMPDEF Import definition record. See the IMPDEF section in this document for a complete description. 02 EXPDEF Export definition record. See the EXPDEF section in this document for a complete description. 03 INCDEF Incremental compilation record. See the INCDEF section in this document for a complete description. 04 Protected LINK386 only; relevant only to 32- memory bit dynamic-link libraries (DLLs). library This comment record is inserted in an object module by the compiler when it encounters the _loadds construct in the source code for a DLL. LINK then sets a flag in the header of the executable file (DLL) to indicate that the DLL should be loaded in such a way that its shared data is protected from corruption. The _loadds keyword tells the compiler to emit modified function prolog code, which loads the DS segment register. (Normal functions don't need this.) When the flag is set in the .EXE header, the loader loads the selector of a protected memory area into DS while performing run-time fixups (relocations). All other DLLs and applications get the regular DGROUP selector, which doesn't allow access to the protected memory area set up by the operating system. 05 LNKDIR C++ linker directives record. See the LNKDIR section of this document for a complete description. 06 Big- The target for this OMF is a big- endian endian machine, as opposed to little- endian or Intel format. (For an explanation of big-endian and little- endian, see "On Holy Wars and a Plea for Peace," by Danny Cohen, pages 48- 54 in "Computer," volume 14, number 10, October 1981.) 07 PRECOMP When the CodeView information for this object file is emitted, the directory entry for $$TYPES is to be emitted as sstPreComp instead of sstTypes. 08-FF Reserved by Microsoft. NOTE: The presence of any unrecognized subtype (currently, anything greater than 07) causes LINK to generate a fatal error. A1 "New OMF" This comment class is now used solely to extension indicate the version of the symbolic debug information. If this comment class is not present, the oldest format of CodeView information is written to the .EXE file produced by LINK. If the comment class is present, the latest version format of CodeView information is written. This comment class was previously used to indicate that the obsolete method of communal representation through TYPDEF and EXTDEF pairs was not used and that COMDEF records were used instead. In current linkers, COMDEF records are always enabled, even without this comment record present. The byte string is currently empty, but the planned future contents will be a version number (8-bit numeric field) followed by an ASCII character string indicating the symbol style. Values will be: n,'C','V CodeView style n,'D','X' AIX style A2 LINK Pass This record conveys information to the linker about the organization of the file. The value of the first byte of the commentary string specifies the comment subtype. Currently, a single subtype is defined: 01 Indicates the start of records generated from LINK Pass 2. Additional bytes may follow, with their number determined by the Record Length field, but they will be ignored by LINK. See the "Order of Records" section in this document for information on which records must come before and after this comment. Warning: It is assumed that this comment will not be present in a module whose MODEND record contains a program starting address. If there are overlays, LINK needs to see the starting address on Pass 1 to define the symbol $$MAIN. NOTE: This comment class may become obsolete with the advent of COMDAT records. A3 LIBMOD Library module comment record. Ignored by LINK; used only by Microsoft's LIB utility. See the LIBMOD section in this document for a complete description. A4 EXESTR Executable string. See the EXESTR section in this document for a complete description. A6 INCERR Incremental compilation error. See the INCERR section in this document for a complete description. A7 NOPAD No segment padding. See the NOPAD section in this document for a complete description. A8 WKEXT Weak Extern record. See the WKEXT section in this document for a complete description. A9 LZEXT Lazy Extern record. See the LZEXT section in this document for a complete description. AA PharLap Possibly obsolete; see the PharLap section format in this document for a complete description. B0 Initial IBM Obsolete. OMF386 format. B1 Record order Obsolete; part of initial IBM OMF386 format. DA Comment For random comment. DB Compiler For pragma comment(compiler); version number. DC Date For pragma comment(date stamp). DD Timestamp For pragma comment(timestamp). DF User For pragma comment(user). Sometimes used for copyright notices. E9 Dependency Used to show the include files that were file used to build this .OBJ file. (Borland) FF Command line Shows the compiler options chosen. May be (QuickC) obsolete. This record is also used by Phoenix for library comments. C0H- Reserved Reserved for user-defined comment classes. FFH and not other- wise used NOTES Microsoft LIB ignores the Comment Type field. A COMENT record can appear almost anywhere in an object module. Only two restrictions apply: - A COMENT record cannot be placed between a FIXUPP record and the LEDATA or LIDATA record to which it refers. - A COMENT record cannot be the first or last record in an object module. (The first record must always be THEADR or LHEADR and the last must always be MODEND.) Examples -------- The following three examples are typical COMENT records taken from an object module generated by the Microsoft C Compiler. This first example is a language-translator comment: 0 1 2 3 4 5 6 7 8 9 A B C D E F 0000 88 07 00 00 00 4D 53 20 43 6E .....MS Cn Byte 00H contains 88H, indicating that this is a COMENT record. Bytes 01-02H contain 0007H, the length of the remainder of the record. Byte 03H (the Comment Type field ) contains 00H. Bit 7 (no purge) is set to 0, indicating that this COMENT record may be purged from the object module by a utility program that manipulates object modules. Bit 6 (no list) is set to 0, indicating that this comment need not be excluded from any listing of the module's contents. The remaining bits are all 0. Byte 04H (the Comment Class field) contains 00H, indicating that this COMENT record contains the name of the language translator that generated the object module. Bytes 05H through 08H contain the name of the language translator, Microsoft C. Byte 09H contains the Checksum field, 6EH. The second example contains the name of an object library to be searched bydefault when LINK processes the object module containing this COMENT record: 0 1 2 3 4 5 6 7 8 9 A B C D E F 0000 88 09 00 00 9F 53 4C 49 42 46 50 10 .....SLIBFP Byte 04H (the Comment Class field) contains 9FH, indicating that this record contains the name of a library for LINK to use to resolve external references. Bytes 05-0AH contain the library name, SLIBFP. In this example, the name refers to the Microsoft C Compiler's floating-point function library, SLIBFP.LIB. The last example indicates that LINK should write the most recent format of CodeView information to the executable file. 0 1 2 3 4 5 6 7 8 9 A B C D E F 0000 88 06 00 00 A1 01 43 56 37 .....CV7 Byte 04H indicates the comment class, 0A1H. Bytes 05-07H, which contain the comment string, are ignored by LINK. 88H IMPDEF--Import Definition Record (Comment Class A0, Subtype 01) =================================================================== Description ----------- This record describes the imported names for a module. History ------- This comment class and subtype is a Microsoft extension added for OS/2 and Windows. Record Format ------------- One import symbol is described; the subrecord format is 1 1 2 or 01 Ordinal Internal Module Entry Flag Name Name Ident where: 01 Identifies the subtype as an IMPDEF. It determines the form of the Entry Ident field. Ordinal Flag Is a byte; if 0, the import is identified by name. If nonzero, it is identified by ordinal. It determines the form of the Entry Ident field. Internal Name Is in string format and is the name used within this module for the import symbol. This name will occur again in an EXTDEF record. Module Name Is in string format and is the name of the module (a DLL) that supplies an export symbol matching this import. Entry Ident Is an ordinal or the name used by the exporting module for the symbol, depending upon the Ordinal Flag. If this field is an ordinal (Ordinal Flag is nonzero), it is a 16-bit word. If this is a name and the first byte of the name is 0, then the exported name is the same as the imported name (in the Internal Name field). Otherwise, it is the imported name in string format (as exported by Module Name). NOTE: IMPDEF records are created by the utility IMPLIB, which builds an "import library" from a module definition file or DLL. 88H EXPDEF--EXPORT DEFINITION RECORD (COMMENT CLASS A0, SUBTYPE 02) =================================================================== Description ----------- This record describes the exported names for a module. History ------- This comment class and subtype is a Microsoft extension added for C version 5.1. Record Format ------------- One exported entry point is described; the subrecord format is 1 1 2 02 Exported Exported Internal Export Flag Name Name Ordinal where: 02 Identifies the subtype as an EXPDEF. Exported Flag Is a bit-significant 8-bit field with the following format: <-----------------------1 byte----------------------------> Ordinal Resident No Parm Count Bit Name Data 1 1 1 <---------5 bits-------> Ordinal Bit Is set if the item is exported by ordinal; in this case the Export Ordinal field is present. Resident Is set if the exported name is to be kept Name resident by the system loader; this is an optimization for frequently used items imported by name. No Data Is set if the entry point does not use initialized data (either instanced or global). Parm Count Is the number of parameter words. The Parm Count field is set to 0 for all but callgates to 16-bit segments. Exported Name Is in string format. Name to be used when the entry point is imported by name. Internal Name Is in string format. If the name length is 0, the internal name is the same as the Exported Name field. Otherwise, it is the name by which the entry point is known within this module. This name will appear as a PUBDEF or LPUBDEF name. Export Ordinal Is present if the Ordinal Bit field is set; it is a 16-bit numeric field whose value is the ordinal used (must be nonzero). NOTES EXPDEFs are produced by Microsoft compilers when the keyword _export is used in a source file. Microsoft LINK limits the value of the Export Ordinal field to 16,384 bytes (16K) or less. 88H INCDEF--INCREMENTAL COMPILATION RECORD (COMMENT CLASS A0, SUBTYPE 03) ========================================== Description ----------- This record is used for incremental compilation. Every FIXUPP and LINNUM record following an INCDEF record will adjust all external index values and line number values by the appropriate delta. The deltas are cumulative if there is more than one INCDEF record per module. History ------- This comment class subtype is a Microsoft extension added for QuickC version 2.0. Record Format ------------- The subrecord format is: 1 2 2 03 EXTDEF LINNUM Padding Delta Delta The EXTDEF Delta and LINNUM Delta fields are signed. Padding (zeros) is added by QuickC to allow for expansion of the object module during incremental compilation and linking. NOTE: Negative deltas are allowed. 88H LNKDIR--C++ DIRECTIVES RECORD (COMMENT CLASS A0, SUBTYPE 05) =================================------------------------------- Description ----------- This record is used by the compiler to pass directives and flags to the linker. History ------- This comment class and subtype is a Microsoft extension added for C 7.0. Record Format ------------- The subrecord format is: 1 1 1 1 05 Bit Pseudocode CodeView Flags Version Version Bit Flags Field --------------- The format of the Bit Flags byte is: 8 1 1 1 1 1 1 1 1 (bits) 05 0 0 0 0 0 Run Omit New MPC CodeView .EXE $PUBLICS The low-order bit, if set, indicates that LINK should output the new .EXE format; this flag is ignored for all but linking of pseudocode (p- code) applications. (Pseudocode requires a segmented executable.) The second low-order bit indicates that LINK should not output the $PUBLICS subsection of the CodeView information. The third low-order bit indicates that MPC (the Make Pseudocode utility) should be run. Pseudocode Version Field ------------------------ This field is one byte indicating the pseudocode interpreter version number. CodeView Version Field ---------------------- This field is one byte indicating the CodeView version number. NOTE: The presence of this record in an object module will indicate the presence of global symbols records. The linker will not emit a $PUBLICS section for those modules with this comment record and a $SYMBOLS section. 88H LIBMOD--LIBRARY MODULE NAME RECORD (COMMENT CLASS A3) ========================================================= Description ----------- The LIBMOD comment record is used only by the LIB utility, not by LINK. It gives the name of an object module within a library, allowing LIB to preserve the source filename in the THEADR record and still identify the module names that make up the library. Since the module name is the base name of the .OBJ file that was built into the library, it may be completely different from the final library name. History ------- This comment class and subtype is a Microsoft extension added for LIB version 3.07 in MASM version 5.0. Record Format ------------- The subrecord format is: 1 A3 Module Name The record contains only the ASCII string of the module name, in format. The module name has no path and no extension, just the base of the module name. NOTES LIB adds a LIBMOD record when an .OBJ file is added to a library and strips the LIBMOD record when an .OBJ file is removed from a library, so typically this record exists only in .LIB files. There will be one LIBMOD record in the library file for each object module that was combined to build the library. 88H EXESTR--EXECUTABLE STRING RECORD (COMMENT CLASS A4) ======================================================= Description ----------- The EXESTR comment record implements these ANSI and XENIX/UNIX features in C: #pragma comment(exestr, ) #ident string History ------- This comment class and subtype is a Microsoft extension added for C 5.1. Record Format ------------- The subrecord format is: 1 A4 Arbitrary Text The linker will copy the text in the Arbitrary Text field byte for byte to the end of the executable file. The text will not be included in the program load image. NOTE: If CodeView information is present, the text will not be at the end of the file but somewhere before so as not to interfere with the CodeView signature. There is no limit to the number of EXESTR comment records. 88H INCERR--INCREMENTAL COMPILATION ERROR (COMMENT CLASS A6) ============================================================ Description ----------- This comment record will cause the linker to terminate with a fatal error similar to "invalid object--error encountered during incremental compilation." This behavior is useful when an incremental compilation fails and the user tries to link manually. The object module cannot be deleted, in order to preserve the base for the next incremental compilation. History ------- This comment class and subtype is a Microsoft extension added for QuickC 2.0. Record Format ------------- The subrecord format is: 1 A6 No Fields 88H NOPAD--NO SEGMENT PADDING (COMMENT CLASS A7) ================================================ Description ----------- This comment record identifies a set of segments that are to be excluded from the padding imposed with the /PADDATA or /PADCODE options. History ------- This comment class and subtype is a Microsoft extension added for COBOL. It was added to LINK to support MicroFocus COBOL version 1.2; it was added permanently in LINK version 5.11 to support Microsoft COBOL version 3.0. Record Format ------------- The subrecord format is: 1 1 or 2 A7 SEGDEF Index <---------repeated----------> The SEGDEF Index field is the standard OMF index type of 1 or 2 bytes. It may be repeated. 88H WKEXT--WEAK EXTERN RECORD (COMMENT CLASS A8) ================================================ Description ----------- This record marks a set of external names as "weak," and for every weak extern, the record associates another external name to use as the default resolution. History ------- This comment class and subtype is a Microsoft extension added for Basic version 7.0. There is no construct in Basic that produces it, but the record type is manually inserted into Basic library modules. The first user-accessible construct to produce a weak extern was added for MASM version 6.0. See the "Notes" section below for details on how and why this record is used in Basic and MASM. Record Format ------------- The subrecord format is: 1 1 or 2 1 or 2 A8 Weak EXTDEF Default Resolution Index EXTDEF Index <------------repeated------------> The Weak EXTDEF Index field is the 1- or 2-byte index to the EXTDEF of the extern that is weak. The Default Resolution EXTDEF Index field is the 1- or 2-byte index to the EXTDEF of the extern that will be used to resolve the extern if no "stronger" link is found to resolve it. NOTES There are two ways to cancel the "weakness" of a weak extern; both result in the extern becoming a "strong" extern (the same as an EXTDEF). They are: -If a PUBDEF for the weak extern is linked in -If an EXTDEF for the weak extern is found in another module (including libraries) If a weak extern becomes strong, then it must be resolved with a matching PUBDEF, just like a regular EXTDEF. If a weak extern has not become strong by the end of the linking process, then the default resolution is used. If two weak externs for the same symbol in different modules have differing default resolutions, LINK will emit a warning. Weak externs do not query libraries for resolution; if an extern is still weak when libraries are searched, it stays weak and gets the default resolution. However, if a library module is linked in for other reasons (say, to resolve strong externs) and there are EXTDEFs for symbols that were weak, the symbols become strong. For example, suppose there is a weak extern for "var" with a default resolution name of "con". If there is a PUBDEF for "var" in some library module that would not otherwise be linked in, then the library module is not linked in, and any references to "var" are resolved to "con". However, if the library module is linked in for other reasons--for example, to resolve references to a strong extern named "bletch"-- then "var" will be resolved by the PUBDEF from the library, not to the default resolution "con". WKEXTs are best understood by explaining why they were added in the first place. The minimum Basic run-time library in the past consisted of a large amount of code that was always linked in, even for the smallest program. Most of this code was never called directly by the user, but it was called indirectly from other routines in other libraries, so it had to be linked in to resolve the external references. For instance, the floating-point library was linked in even if the user's program did not use floating-point operations, because the PRINT library routine contained calls to the floating-point library for support to print floating-point numbers. The solution was to make the function calls between the libraries into weak externals, with the default resolution set to a small stub routine. If the user never used a language construct or feature that needed the additional library support, then no strong extern would be generated by the compiler and the default resolution (to the stub routine) would be used. However, if the user accessed the library's routines or used constructs that required the library's support, a strong extern would be generated by the compiler to cancel the effect of the weak extern, and the library module would be linked in. This required that the compiler know a lot about which libraries are needed for which constructs, but the resulting executable was much smaller. The construct in MASM 6.0 that produces a weak extern is EXTERN var(con): byte which makes "con" the default resolution for weak extern "var". ********** Document 3 ********** 88H LZEXT--LAZY EXTERN RECORD (COMMENT CLASS A9) ================================================ Description ----------- This record marks a set of external names as "lazy," and for every lazy extern, the record associates another external name to use as the default resolution. History ------- This comment class and subtype is a Microsoft extension added for C 7.0, but was not implemented in the C 7.0 linker. Record Format ------------- The subrecord format is: 1 1 or 2 1 or 2 A9 Lazy EXTDEF Default Resolution Index EXTDEF Index <---------------repeated-------------> The Lazy EXTDEF Index field is the 1- or 2-byte index to the EXTDEF of the extern that is lazy. The Default Resolution EXTDEF Index field is the 1- or 2-byte index to the EXTDEF of the extern that will be used to resolve the extern if no "stronger" link is found to resolve it. NOTES There are two ways to cancel the "laziness" of a lazy extern; both result in the extern becoming a "strong" extern (the same as an EXTDEF.) They are: - If a PUBDEF for the lazy extern is linked in - If an EXTDEF for the lazy extern is found in another module (including libraries) If a lazy extern becomes strong, it must be resolved with a matching PUBDEF, just like a regular EXTDEF. If a lazy extern has not become strong by the end of the linking process, then the default resolution is used. If two weak externs for the same symbol in different modules have differing default resolutions, LINK will emit a warning. Unlike weak externs, lazy externs do query libraries for resolution; if an extern is still lazy when libraries are searched, it stays lazy and gets the default resolution. 88H PHARLAP FORMAT RECORD (COMMENT CLASS AA) ============================================ Description ----------- The OMF extension designed by PharLap is called "Easy OMF-386." Changes to the affected record types are described in this section. Most modifications involve only a substitution of 32-bit (4-byte) fields for what were formerly 16-bit (2-byte) fields. In the two cases where the changes involve more than just a field size (in the SEGDEF and FIXUPP records), the information is mentioned in this section, but complete details are given in the sections describing the specific records. History ------- This format is described as "obsolete" in the expectation that negotiations between Microsoft and PharLap will result in convergence to the new "standard." However, its obsolescence needs to be verified. When the new standard is agreed upon, Microsoft encourages you to adopt it. Record Format ------------- The format of the comment's subrecord is: AA "80386" NOTES The AA comment record should come immediately after the sole THEADR record. Presence of the comment record indicates that the following other record types have fields that are expanded from 16-bit to 32- bit values: SEGDEF Offset field and Segment Length field PUBDEF Public Offset field LEDATA Enumerated Data Offset field LIDATA Iterated Data Offset field (note that the Repeat Count field is still 16 bits) FIXUPP Target Displacement field in an explicit FIXUP subrecord BLKDEF Return Address Offset field LINNUM Line Number Offset field MODEND Target Displacement field FIXUPP records have the added LOCATION values of 5 and 6, which conflict with the Microsoft 32-bit extensions to this field. See the FIXUPP section of this document for details. SEGDEF records have added alignment values (for 4-byte alignment and 4K alignment) and an added optional byte at the end that contains the Use16/Use32 bit flag and access attributes (read/write/execute) for the segment. The alignment values are the same as Microsoft's 32- bit extensions to the field, but the attributes stored in the added byte conflict with Microsoft's way of specifying those attributes. See the SEGDEF sectionof this document for details. 8AH OR 8BH MODEND--MODULE END RECORD ==================================== Description ----------- The MODEND record denotes the end of an object module. It also indicates whether the object module contains the main routine in a program, and it can optionally contain a reference to a program's entry point. History ------- Record type 8BH is new for LINK386; it has a Target Displacement field of 32 bits rather than 16 bytes. An IBM extension to this record type (initial values for segment registers) was proposed for LINK386 but was never implemented. Record Format ------------- 1 2 1 1 1 or 2 1 or 2 2 or 4 1 8A Record Module End Data Frame Target Target Checksum or Length Type Datum Datum Displace- 8B ment <-Start Address subfield, conditional-> where: Module Type Field The Module Type byte is bit significant; its layout is MATTR Segment Main Start Bit 0 0 0 0 X <--2 bits--> where: MATTR Is a 2-bit field. Main Is set if the module is a main program module. Start Is set if the module contains a start address; if this bit is set, the field starting with the End Data byte is present and specifies the start address. Segment Bit Is reserved by IBM. Only 0 is supported by MS-DOS and OS/2. X Is set if the Start Address subfield contains a relocatable address reference that LINK must fix up. (The Intel specification allows this bit to be 0, to indicate that the start address is an absolute physical address that is stored as a 16-bit frame number and 16-bit offset, but this capability is not supported by LINK.) This bit should always be set; however, the value will be ignored. Start Address The Start Address subfield is present only if the Start bit in the Module Type byte is set. Its format is identical to the Fix Data, Frame Datum, Target Datum, and Target Displacement fields in a FIXUP subrecord of a FIXUPP record. Bit 2 of the End Data field, which corresponds to the P bit in a Fix Data field, must be 0. The Target Displacement field (if present) is a 4-byte field if the record type is 8BH and a 2- byte field otherwise. This value provides the initial contents of CS:(E)IP. If overlays are used, the start address must be given in the MODEND record of the root module. NOTES A MODEND record can appear only as the last record in an object module. It is assumed that the Link Pass Separator comment record (COMENT A2, subtype 01) will not be present in a module whose MODEND record contains a program starting address. If there are overlays, LINK needs to see the starting address on Pass 1 to define the symbol $$MAIN. Examples -------- Consider the MODEND record of a simple HELLO.ASM program: 0 1 2 3 4 5 6 7 8 9 A B C D E F 0000 8A 07 00 C1 00 01 01 00 00 AC..... Byte 00H contains 8AH, indicating a MODEND record. Bytes 01-02H contain 0007H, the length of the remainder of the record. Byte 03H contains 0C1H (11000001B). Bit 7 is set to 1, indicating that this module is the main module of the program. Bit 6 is set to 1, indicating that a Start Address subfield is present. Bit 0 is set to 1, indicating that the address referenced in the Start Address subfield must be fixed up by LINK. Byte 04H (End Data in the Start Address subfield) contains 00H. As in a FIXUPP record, bit 7 indicates that the frame for this fixup is specified explicitly, and bits 6 through 4 indicate that a SEGDEF index specifies the frame. Bit 3 indicates that the target reference is also specified explicitly, and bits 2 through 0 indicate that a SEGDEF index also specifies the target. See also "9CH or 9DH FIXUPP-- Fixup Record" in this document. Byte 05H (Frame Datum in the Start Address subfield) contains 01H. This is a reference to the first SEGDEF record in the module, which in this example corresponds to the _TEXT segment. This reference tells LINK that the start address lies in the _TEXT segment of the module. Byte 06H (Target Datum in the Start Address subfield) contains 01H. This also is a reference to the first SEGDEF record in the object module, which corresponds to the _TEXT segment. LINK uses the following Target Displacement field to determine where in the _TEXT segment the address lies. Bytes 07-08H (Target Displacement in the Start Address subfield) contain 0000H. This is the offset (in bytes) of the start address. Byte 09H contains the Checksum field, 0ACH. 8CH EXTDEF--EXTERNAL NAMES DEFINITION RECORD ============================================ Description ----------- The EXTDEF record contains a list of symbolic external references-- that is, references to symbols defined in other object modules. The linker resolves external references by matching the symbols declared in EXTDEF records with symbols declared in PUBDEF records. History ------- In the Intel specification and older linkers, the Type Index field was used as an index into TYPDEF records. This is no longer true; the field now encodes CodeView type information (see Appendix 1 for details.) LINK ignores the old style TYPDEF. Record Format ------------- 1 2 1 1 or 2 1 8C Record String External Type Index Checksum Length Length Name String This record provides a list of unresolved references, identified by name and with optional associated type information. The external names are ordered by occurrence jointly with the COMDEF and LEXTDEF records, and referenced by an index in other records (FIXUPP records); the name may not be null. Indexes start from 1. String Length is a 1-byte field containing the length of the name field that follows it. LINK restricts the name length to a value between 1 and 7FH. The Type Index field is encoded as an index field and contains proprietary CodeView-type information. At this time, the linker does not perform any type checking. NOTES For Microsoft compilers, all referenced functions of global scope and all referenced variables explicitly declared "extern" will generate an EXTDEF record. LINK imposes a limit of 1023 external names. Any EXTDEF records in an object module must appear before the FIXUPP records that reference them. Resolution of an external reference is by name match (case sensitive) and symbol type match. The search looks for a matching name in the following sequence: 1. Searches PUBDEF and COMDEF records. 2. If linking a segmented executable, searches imported names (IMPDEF). 3. If linking a segmented executable and not a DLL, searches for an exported name (EXPDEF) with the same name--a self-imported alias. 4. Searches for the symbol name among undefined symbols. If the reference is to a weak extern, the default resolution is used. If the reference is to a strong extern, it's an undefined external, and LINK generates an error. All external references must be resolved at link time (using the above search order). Even though LINK produces an executable file for an unsuccessful link session, an error bit is set in the header that prevents the loader from running the executable. Examples -------- Consider this EXTDEF record generated by the Microsoft C Compiler: 0 1 2 3 4 5 6 7 8 9 A B C D E F 0000 8C 25 00 0A 5F 5F 61 63 72 74 75 73 65 64 00 05 .%.__acrtused.. 0010 5F 6D 61 69 6E 00 05 5F 70 75 74 73 00 08 5F 5F _main.._puts..__ 0020 63 68 6B 73 74 6B 00 A5 chkstk.. Byte 00H contains 8CH, indicating that this is an EXTDEF record. Bytes 01-02H contain 0025H, the length of the remainder of the record. Bytes 03-26H contain a list of external references. The first reference starts in byte 03H, which contains 0AH, the length of the name __acrtused. The name itself follows in bytes 04-0DH. Byte 0EH contains 00H, which indicates that the symbol's type is not defined by any TYPDEF record in this object module. Bytes 0F-26H contain similar references to the external symbols _main, _puts, and __chkstk. Byte 27H contains the Checksum field, 0A5H. 8EH TYPDEF--TYPE DEFINITION RECORD ================================== Description ----------- The TYPDEF record contains details about the type of data represented by a name declared in a PUBDEF or an EXTDEF record. This information may be used by a linker to validate references to names, or it may be used by a debugger to display data according to type. Although the original Intel specification allowed for many different type specifications, such as scalar, pointer, and mixed data structure, LINK used TYPDEF records to declare only communal variables. Communal variables represent globally shared memory areas-- for example, FORTRAN common blocks or uninitialized public variables in C. The size of a communal variable is declared explicitly in the TYPDEF record. If a communal variable has different sizes in different object modules, LINK uses the largest declared size when it generates an executable module. History ------- Starting with Microsoft LINK version 3.5, the COMDEF record should be used for declaration of communal variables. However, for compatibility, later versions of LINK recognize TYPDEF records as well as COMDEF records. Record Format ------------- 1 2 1 1 8E Record Name 0 Leaf Checksum Length (EN) Descriptor The name field of a TYPDEF record is in format and is always ignored. It is usually a 1-byte field containing a single 0 byte. The Eight-Leaf Descriptor field in the original Intel specification was a variable-length (and possibly repeated) field that contained as many as eight "leaves" that could be used to describe mixed data structures. Microsoft uses a stripped-down version of the Eight-Leaf Descriptor, of which the first byte, the EN byte, is always set to 0. The Leaf Descriptor field is a variable-length field that describes the type and size of a variable. The two possible variable types are NEAR and FAR. If the field describes a NEAR variable (one that can be referenced as an offset within a default data segment), the format of the Leaf Descriptor field is: 1 1 62H Variable Length in Bits Type The 1-byte field containing 62H signifies a NEAR variable. The Variable Type field is a 1-byte field that specifies the variable type: 77H Array 79H Structure 7BH Scalar This field must contain one of the three values given above, but the specific value is ignored by LINK. The Length in Bits field is a variable-length field that indicates the size of the communal variable. Its format depends on the size it represents. If the first byte of the size is 128 (80H) or less, then the size is that value. If the first byte of the size is 81H, then a 2-byte size follows. If the first byte of the size is 84H, then a 3-byte size follows. If the first byte of the size is 88H, then a 4-byte size follows. If the Leaf Descriptor field describes a FAR variable (one that must be referenced with an explicit segment and offset), the format is: 1 1 61H Variable Number of Elements Element Type Index Type (77H) The 1-byte field containing 61H signifies a FAR variable. The 1-byte variable type for a FAR communal variable is restricted to 77H (array). (As with the NEAR Variable Type field, LINK ignores this field, but it must have the value 77H.) The Number of Elements field is a variable-length field that contains the number of elements in the array. It has the same format as the Length in Bits field in the Leaf Descriptor field for a NEAR variable. The Element Type Index field is an index field that references a previous TYPDEF record. A value of 1 indicates the first TYPDEF record in the object module, a value of 2 indicates the second TYPDEF record, and so on. The TYPDEF record referenced must describe a NEAR variable. This way, the data type and size of the elements in the array can be determined. NOTE: LINK limits the number of TYPDEF records in an object module to 256. Examples -------- The following three examples of TYPDEF records were generated by Microsoft C Compiler version 3.0. (Later versions use COMDEF records.) The first sample TYPDEF record corresponds to the public declaration: int var; /* 16-bit integer */ The TYPDEF record is: 0 1 2 3 4 5 6 7 8 9 A B C D E F 0000 8E 06 00 00 00 62 7B 10 7F .....b{.. Byte 00H contains 8EH, indicating that this is a TYPDEF record. Bytes 01-02H contain 0006H, the length of the remainder of the record. Byte 03H (the name field) contains 00H, a null name. Bytes 04-07H represent the Eight-Leaf Descriptor field. The first byte of this field (byte 04H) contains 00H. The remaining bytes (bytes 05- 07H) represent the Leaf Descriptor field: - Byte 05H contains 62H, indicating that this TYPDEF record describes a NEAR variable. - Byte 06H (the Variable Type field) contains 7BH, which describes this variable as scalar. - Byte 07H (the Length in Bits field) contains 10H, the size of the variable in bits. Byte 08H contains the Checksum field, 7FH. The next example demonstrates how the variable size contained in the Length in Bits field of the Leaf Descriptor field is formatted: char var2[32768]; /* 32 KB array */ The TYPDEF record is: 0 1 2 3 4 5 6 7 8 9 A B C D E F 0000 8E 09 00 00 00 62 7B 84 00 00 04 04 .....bc{..... The Length in Bits field (bytes 07-0AH) starts with a byte containing 84H, which indicates that the actual size of the variable is represented as a 3-byte value (the following three bytes). Bytes 08- 0AH contain the value 040000H, the size of the 32K array in bits. This third C statement, because it declares a FAR variable, causes two TYPDEF records to be generated: char far var3[10][2][20]; /* 400-element FAR array*/ The two TYPDEF records are: 0 1 2 3 4 5 6 7 8 9 A B C D E F 0000 8E 06 00 00 62 7B 08 87 8E 09 00 00 00 00 61 77 ....bc{......aw 0010 81 90 01 01 7E .....| Bytes 00-08H contain the first TYPDEF record, which defines the data type of the elements of the array (NEAR, scalar, 8 bits in size). Bytes 09-14H contain the second TYPDEF record. The Leaf Descriptor field of this record declares that the variable is FAR (byte 0EH contains 61H) and an array (byte 0FH, the variable type, contains 77H). NOTE: Because this TYPDEF record describes a FAR variable, bytes 10- 12H represent a Number of Elements field. The first byte of the field is 81H, indicating a 2-byte value, so the next two bytes (bytes 11-12H) contain the number of elements in the array, 0190H (400D). Byte 13H (the Element Type Index field) contains 01H, which is a reference to the first TYPDEF record in the object module--in this example, the one in bytes 00-08H. 90H OR 91H PUBDEF--PUBLIC NAMES DEFINITION RECORD ================================================= Description ----------- The PUBDEF record contains a list of public names. It makes items defined in this object module available to satisfy external references in other modules with which it is bound or linked. The symbols are also available for export if so indicated in an EXPDEF comment record. History ------- Record type 91H is new for LINK386; it has a Public Offset field of 32 bits rather than 16 bits. Record Format ------------- 1 2 1 or 2 1 or 2 2 1 -------------------------------------------------------------------------- 90 Record Base Base Base String Public Public Type Check or Length Group Segment Frame Length Name String Offset Index sum 91 -------------------------------------------------------------------------- tional> Base Group, Base Segment, and Base Frame Fields ----------------------------------------------- The Base Group and Base Segment fields are indexes specifying previously defined SEGDEF and GRPDEF records. The group index may be 0, meaning that no group is associated with this PUBDEF record. The Base Frame field is present only if the Base Segment field is 0, but the contents of the Base Frame field are always ignored by LINK. The segment index is normally nonzero and no Base Frame field is present. According to the Intel specification, if both the segment and group indexes are 0, the Base Frame field contains a 16-bit paragraph (when viewed as a linear address); this may be used to define public symbols that are absolute. Absolute addressing is not fully supported by LINK- -it can be used for read-only access to absolute memory locations; however, writing to absolute memory locations may not work in current linkers. This feature is so rarely used that it should be considered unsupported. Public Name String, Public Offset, and Type Index Fields -------------------------------------------------------- The Public Name String field is in form and cannot be null. Microsoft LINK restricts the maximum length of a public name to 255 bytes. The Public Offset field is a 2- or 4-byte numeric field containing the offset of the location referred to by the public name. This offset is assumed to lie within the group, segment, or frame specified in the Base Group, Base Segment, or Base Frame fields. The Type Index field is encoded in index format; it contains either proprietary CodeView-type information or an old-style TYPDEF index. If this index is 0, there is no associated type data. Old-style TYPDEF indexes are ignored by LINK. Current linkers perform no type checking. NOTES All defined functions and initialized global variables generate PUBDEF records in Microsoft compilers. No PUBDEF record will be generated, however, for instantiated inline functions in C++. Any PUBDEF records in an object module must appear after the GRPDEF and SEGDEF records to which they refer. Because PUBDEF records are not themselves referenced by any other type of object record, they are generally placed near the end of an object module. Record type 90H uses 16-bit encoding of the Public Offset field, but it is zero-extended to 32 bits if applied to Use32 segments. Examples -------- The following two examples show PUBDEF records created by MASM. The first example is the record for the statement: PUBLIC GAMMA The PUBDEF record is: 0 1 2 3 4 5 6 7 8 9 A B C D E F 0000 90 0C 00 00 01 05 47 41 4D 4D 41 02 00 00 F9 .....GAMMA..... Byte 00H contains 90H, indicating a PUBDEF record. Bytes 01-02H contain 000CH, the length of the remainder of the record. Bytes 03-04H represent the Base Group, Base Segment, and Base Frame fields. Byte 03H (the group index) contains 0, indicating that no group is associated with the name in this PUBDEF record. Byte 04H (the segment index) contains 1, a reference to the first SEGDEF record in the object module. This is the segment to which the name in this PUBDEF record refers. Bytes 05-0AH represent the Public Name String field. Byte 05H contains 05H (the length of the name), and bytes 06-0AH contain the name itself, GAMMA. Bytes 0B-0CH contain 0002H, the Public Offset field. The name GAMMA thus refers to the location that is offset two bytes from the beginning of the segment referenced by the Base Group, Base Segment, and Base Frame fields. Byte 0DH is the Type Index field. The value of the Type Index field is 0, indicating that no data type is associated with the name GAMMA. Byte 0EH contains the Checksum field, 0F9H. The next example is the PUBDEF record for the following absolute symbol declaration: PUBLIC ALPHA ALPHA EQU 1234h The PUBDEF record is: 0 1 2 3 4 5 6 7 8 9 A B C D E F 0000 90 0E 00 00 00 00 00 05 41 4C 50 48 41 34 12 00 ...ALPHA4... 0010 B1 Bytes 03-06H (the Base Group, Base Segment, and Base Frame fields) contain a group index of 0 (byte 03H) and a segment index of 0 (byte 04H). Since both the group index and segment index are 0, a frame number also appears in the Base Group, Base Segment, and Base Frame fields. In this instance, the frame number (bytes 05-06H) also happens to be 0. Bytes 07-0CH (the Public Name String field) contain the name ALPHA, preceded by its length. Bytes 0D-0EH (the Public Offset field) contain 1234H. This is the value associated with the symbol ALPHA in the assembler EQU directive. If ALPHA is declared in another object module with the declaration EXTRN ALPHA:ABS any references to ALPHA in that object module are fixed up as absolute references to offset 1234H in frame 0. In other words, ALPHA would have the value 1234H. Byte 0FH (the Type Index field) contains 0. 94H OR 95H LINNUM--LINE NUMBERS RECORD ====================================== Description ----------- The LINNUM record relates line numbers in source code to addresses in object code. For instantiated inline functions in C 7.0, line numbers will be output in LINSYM records with a reference to the function name instead of the segment. History ------- Record type 95H is new for LINK386; it has a Line Number Offset field of 32 bits rather than 16 bits. Record Format ------------- 1 2 1 or 2 1 or 2 2 2 or 4 1 94 Record Base Base Line Line Number Checksum or Length Group Segment Number Offset 95 <--------repeated------> Base Group and Base Segment Fields ---------------------------------- The Base Group and Base Segment fields are indexes specifying previously defined GRPDEF and SEGDEF records. The Base Group field is ignored, and the Base Segment field must be nonzero. Although the complete Intel specification allows the Base Group and Base Segment fields to refer to a group or to an absolute segment as well as to a relocatable segment, Microsoft restricts references in this field to relocatable segments. Line Number and Line Number Offset Fields ----------------------------------------- The Line Number field is a 16-bit quantity, in the range 0 through 7FFF and is, as its name indicates, a line number in the source code. The Line Number Offset field is a 2- or 4-byte quantity that gives the translated code or data's start byte in the program segment defined by the SEGDEF index (4 bytes if the record type is 95H; 2 bytes for type 94H). The Line Number and Line Number Offset fields can be repeated, so a single LINNUM record can specify multiple line numbers in the same segment. Line Number 0 has a special meaning: it is used for the offset of the first byte after the end of the function. This is done so that the length of the last line (in bytes) can be determined. NOTES The source file corresponding to a line number group is determined from the THEADR record. Any LINNUM records in an object module must appear after the SEGDEF records to which they refer. Because LINNUM records are not themselves referenced by any other type of object record, they are generally placed near the end of an object module. Also see the INCDEF record of this document, which is used to maintain line numbers after incremental compilation. Examples -------- The following LINNUM record was generated by the Microsoft C Compiler: 0 1 2 3 4 5 6 7 8 9 A B C D E F 0000 94 0F 00 00 01 02 00 00 00 03 00 08 00 04 00 0F ........... 0010 00 3C .. Byte 00H contains 94H, indicating that this is a LINNUM record. Bytes 01-02H contain 000FH, the length of the remainder of the record. Bytes 03-04H represent the Base Group and Base Segment fields. Byte 03H (the Base Group field) contains 00H, as it must. Byte 04H (the Base Segment field) contains 01H, indicating that the line numbers in this LINNUM record refer to code in the segment defined in the first SEGDEF record in this object module. Bytes 05-06H (the Line Number field) contain 0002H, and bytes 07-08H (the Line Number Offset field) contain 0000H. Together, they indicate that source-code line number 0002 corresponds to offset 0000H in the segment indicated in the Base Group and Base Segment fields. Similarly, the two pairs of Line Number and Line Number Offset fields in bytes 09-10H specify that line number 0003 corresponds to offset 0008H and that line number 0004 corresponds to offset 000FH. Byte 11H contains the Checksum field, 3CH. ********** Document 4 ********** 96H LNAMES--LIST OF NAMES RECORD ================================ Description ----------- The LNAMES record is a list of names that can be referenced by subsequent SEGDEF and GRPDEF records in the object module. The names are ordered by occurrence and referenced by index from subsequent records. More than one LNAMES record may appear. The names themselves are used as segment, class, group, overlay, and selector names. History ------- This record has not changed since the original Intel 8086 OMF specification. Record Format ------------- 1 2 1 <--String Length--> 1 96 Record String Name String Checksum Length Length <-----------repeated-----------> Each name appears in format, and a null name is valid. The character set is ASCII. Names can be up to 254 characters long. NOTE: Any LNAMES records in an object module must appear before the records that refer to them. Because it does not refer to any other type of object record, an LNAMES record usually appears near the start of an object module. Examples -------- The following LNAMES record contains the segment and class names specified in all three of the following full-segment definitions: _TEXT SEGMENT byte public 'CODE' _DATA SEGMENT word public 'DATA' _STACK SEGMENT para public 'STACK' The LNAMES record is: 0 1 2 3 4 5 6 7 8 9 A B C D E F 0000 96 25 00 00 04 43 4F 44 45 04 44 41 54 41 05 53 .%...CODE.DATA.S. 0010 54 41 43 4B 05 5F 44 41 54 41 06 5F 53 54 41 43 TACK._DATA._STAC 0020 4B 05 5F 54 45 58 54 8B K._TEXT. Byte 00H contains 96H, indicating that this is an LNAMES record. Bytes 01-02H contain 0025H, the length of the remainder of the record. Byte 03H contains 00H, a zero-length name. Byte 04H contains 04H, the length of the class name CODE, which is found in bytes 05-08H. Bytes 09-26H contain the class names DATA and STACK and the segment names _DATA, _STACK, and _TEXT, each preceded by 1 byte that gives its length. Byte 27H contains the Checksum field, 8BH. 98H OR 99H SEGDEF--SEGMENT DEFINITION RECORD ============================================ Description ----------- The SEGDEF record describes a logical segment in an object module. It defines the segment's name, length, and alignment, and the way the segment can be combined with other logical segments at bind, link, or load time. Object records that follow a SEGDEF record can refer to it to identify a particular segment. The SEGDEF records are ordered by occurrence, and are referenced by segment indexes (starting from 1) in subsequent records. History ------- Record type 99H is new for LINK386: the Segment Length field is 32 bits rather than 16 bits, there is one newly implemented alignment type (page alignment), the B bit flag of the ACBP byte indicates a segment of 4 GB, and the P bit flag of the ACBP byte is the Use16/Use32 flag. Starting with version 2.4, LINK ignores the Overlay Name Index field. In versions 2.4 and later, command-line parameters to LINK, rather than information contained in object modules, determine the creation of run-time overlays. The length does not include COMDAT records. If selected, their size is added. Record Format ------------- 1 2 2 or 4 1 or 2 1 or 2 1 or 2 1 98 Record Segment Segment Segment Class Overlay Checksum or 99 Length Attributes Length Name Name Name Index Index Index Segment Attributes Field ------------------------ The Segment Attributes field is a variable-length field; its layout is: <-3 bits-> <-3 bits-> <-1 bit-> <-1 bit-> <-2 bytes--> <--1 byte--> A C B P Frame Number Offset The fields have the following meanings: A Alignment A 3-bit field that specifies the alignment required when this program segment is placed within a logical segment. Its values are: 0 Absolute segment. 1 Relocatable, byte aligned. 2 Relocatable, word (2-byte, 16-bit) aligned. 3 Relocatable, paragraph (16-byte) aligned. 4 Relocatable, aligned on 256-byte boundary (a "page" in the original Intel specification). 5 Relocatable, aligned on a double word (4-byte) boundary. This value is used by the PharLap OMF for the same alignment. 6 This value is used by the PharLap OMF for page (4K) alignment. It is not supported by LINK. 7 Not defined. The new values for LINK386 are A=4 and A=5. Double word alignment is expected to be useful as 32-bit memory paths become more prevalent. Page-align is useful for certain hardware-defined items (such as page tables) and error avoidance. If A=0, the conditional Frame Number and Offset fields are present and indicate the starting address of the absolute segment. LINK ignores the Offset field. Conflict: The original Intel specification included additional segment-alignment values not supported by Microsoft; alignment 5 now conflicts with the following LINK386 extensions: 5 "unnamed absolute portion of memory address space" 6 "load-time locatable (LTL), paragraph aligned if not part of any group" C Combination A 3-bit field that describes how the linker can combine the segment with other segments. Under MS-DOS, segments with the same name and class can be combined in two ways: they can be concatenated to form one logical segment, or they can be overlapped. In the latter case, they have either the same starting address or the same ending address, and they describe a common area in memory. Values for the C field are: 0 Private. Do not combine with any other program segment. 1 Reserved by IBM. Not supported by Microsoft. 2 Public. Combine by appending at an offset that meets the alignment requirement. 3 Reserved by IBM. Not supported by Microsoft. 4 As defined by Microsoft, same as C=2 (public). 5 Stack. Combine as for C=2. This combine type forces byte alignment. 6 Common. Combine by overlay using maximum size. 7 As defined by Microsoft, same as C=2 (public). Conflict: The Intel specification lists C=1 as Common, not C=6. B Big Used as the high-order bit of the Segment Length field. If this bit is set, the segment length value must be 0. If the record type is 98H and this bit is set, the segment is exactly 64K long. If the record type is 99H and this bit is set, the segment is exactly 2^32 bytes, or 4 GB, long. NOTE: A problem in the 286 chip makes code unreliable if it is executed between bytes 65,500 and 65,535. LINK warns of this problem if code segments reach that size. P This bit corresponds to the bit field for segment descriptors, known as the B bit for data segments and the D bit for code segments in the Intel documentation. If 0, then the segment is no larger than 64K (if data), and 16-bit addressing and operands are the default (if code). This is a Use16 segment. If nonzero, then the segment may be larger than 64K (if data), and 32-bit addressing and operands are the default (if code). This is a Use32 segment. NOTE: This is the only method for defining Use32 segments in the Microsoft OMF. The PharLap OMF uses an additional byte of bit flags at the end of the SEGDEF record to hold this and other flags (described later in this section). Even if the P bit is 0, the PharLap OMF assumes all segments are Use32. Segment Length Field -------------------- The Segment Length field is a 2- or 4-byte numeric quantity and specifies the number of bytes in this program segment. For record type 98H, the length can be from 0 to 64K; if a segment is exactly 64K, the segment length should be 0, and the B field in the ACBP byte should be 1. For record type 99H, the length can be from 0 to 4 GB; if a segment is exactly 4 GB in size, the segment length should be 0 and the B field in the ACBP byte should be 1. Segment Name Index, Class Name Index, Overlay Name Index Fields --------------------------------------------------------------- The three name indexes (Segment Name Index, Class Name Index, and Overlay Name Index) refer to names that appeared in previous LNAMES record(s). LINK ignores the Overlay Name Index field. The full name of a segment consists of the segment and class names, and segments in different object modules are normally combined according to the A and C values if their full names are identical. These indexes must be nonzero, although the name itself may be null. The Segment Name Index field identifies the segment with a name. The name need not be unique--other segments of the same name will be concatenated onto the first segment with that name. The name may have been assigned by the programmer, or it may have been generated by a compiler. The Class Name Index field identifies the segment with a class name (such as CODE, FAR_DATA, or STACK). The linker places segments with the same class name into a contiguous area of memory in the run-time memory map. The Overlay Name Index field identifies the segment with a run-time overlay. It is ignored by current versions of the linker. PharLap Extensions to This Record --------------------------------- In the PharLap 32-bit OMF, there is an additional optional field that follows the Overlay Name Index field. The reserved bits should always be 0. The format of this field is <------------5 bits----------------> <--1 bit--> <--2 bits--> Reserved U AT where AT is the access type for the segment and has the following possible values 0 Read only 1 Execute only 2 Execute/read 3 Read/write and U is the Use16/Use32 bit for the segment and has the following possible values: 0 Use16 1 Use32 Conflicts: The Microsoft-defined OMF has Use16/Use32 stored as the P bit of the ACBP field. Microsoft's OMF does not specify the access for the segment--it is specified in the .DEF file given to LINK. NOTES LINK imposes a limit of 255 SEGDEF records per object module. Certain name/class combinations are reserved for use by CodeView and have special significance to the linker: name $$TYPES with class name DEBTYP, and $$SYMBOLS with class name DEBSYM. See Appendix 1 for more information. Examples -------- The following examples of Microsoft assembler SEGMENT directives show the resulting values for the A field in the corresponding SEGDEF object record: aseg SEGMENT at 400h ; A = 0 bseg SEGMENT byte public 'CODE' ; A = 1 cseg SEGMENT para stack 'STACK' ; A = 3 The following examples of assembler SEGMENT directives show the resulting values for the C field in the corresponding SEGDEF object record: aseg SEGMENT at 400H ; C = 0 bseg SEGMENT public 'DATA' ; C = 2 cseg SEGMENT stack 'STACK' ; C = 5 dseg SEGMENT common 'COMMON' ; C = 6 In this first example, the segment is byte aligned: 0 1 2 3 4 5 6 7 8 9 A B C D E F 0000 98 07 00 28 11 00 07 02 01 1E ....(..... Byte 00H contains 98H, indicating that this is a SEGDEF record. Bytes 01-02H contain 0007H, the length of the remainder of the record. Byte 03H contains 28H (00101000B), the ACBP byte. Bits 7-5 (the A field) contain 1 (001B), indicating that this segment is relocatable and byte aligned. Bits 4-2 (the C field) contain 2 (010B), which represents a public combine type. (When this object module is linked, this segment will be concatenated with all other segments with the same name.) Bit 1 (the B field) is 0, indicating that this segment is smaller than 64K. Bit 0 (the P field) is ignored and should be 0, as it is here. Bytes 04-05H contain 0011H, the size of the segment in bytes. Bytes 06-08H index the list of names defined in the module's LNAMES record. Byte 06H (the Segment Name Index field) contains 07H, so the name of this segment is the seventh name in the LNAMES record. Byte 07H (the Class Name Index field) contains 02H, so the segment's class name is the second name in the LNAMES record. Byte 08H (the Overlay Name Index field) contains 1, a reference to the first name in the LNAMES record. (This name is usually null, as MS-DOS ignores it anyway.) Byte 09H contains the Checksum field, 1EH. The second SEGDEF record declares a word-aligned segment. It differs only slightly from the first. 0 1 2 3 4 5 6 7 8 9 A B C D E F 0000 98 07 00 48 0F 00 05 03 01 01 .. H...... Bits 7-5 (the A field) of byte 03H (the ACBP byte) contain 2 (010B), indicating that this segment is relocatable and word aligned. Bytes 04-05H contain the size of the segment, 000FH. Byte 06H (the Segment Name Index field) contains 05H, which refers to the fifth name in the previous LNAMES record. Byte 07H (the Class Name Index field) contains 03H, a reference to the third name in the LNAMES record. 9AH GRPDEF--GROUP DEFINITION RECORD =================================== Description ----------- This record causes the program segments identified by SEGDEF records to be collected together (grouped). For OS/2, the segments are combined into a logical segment that is to be addressed through a single selector. For MS-DOS, the segments are combined within the same 64K frame in the run-time memory map. History ------- The special group name "FLAT" was added for LINK386. Record Format ------------- 1 2 1 or 2 1 1 or 2 1 9A Record Group Name FF Segment Checksum Length Index Index Definition <-----repeated-----> Group Name Field ---------------- The Group Name field is specified as an index into a previously defined LNAMES name and must be nonzero. Groups from different object modules are combined if their names are identical. Group Components ---------------- The group's components are segments, specified as indexes into previously defined SEGDEF records. The first byte of each group component is a type field for the remainder of the component. LINK requires a type value of FFH and always assumes that the component contains a segment index value. See the "Notes" section below for other types defined by Intel. The component fields are usually repeated so that all the segments constituting a group can be included in one GRPDEF record. NOTES LINK imposes a limit of 31 GRPDEF records in a single object module and limits the total number of group definitions across all object modules to 31. This record is frequently followed by a THREAD FIXUPP record. The most common group is DGROUP, which is used to group the default data segments (_DATA, CONST, and _BSS). LINK does special handling of the pseudo-group name FLAT for LINK386 only. All address references to this group are made as offsets from the Virtual Zero Address, which is the start of the memory image of the executable. The additional group component types defined by Intel and the fields that follow them are: FE External Index FD Segment Name Index, Class Name Index, Overlay Name Index FB LTL Data field, Maximum Group Length, Group Length FA Frame Number, Offset None of these types is supported by LINK. Examples -------- The example of a GRPDEF record below corresponds to the following assembler directive: tgroup GROUP seg1,seg2,seg3 The GRPDEF record is: 0 1 2 3 4 5 6 7 8 9 A B C D E F 0000 9A 08 00 06 FF 01 FF 02 FF 03 55 .....U Byte 00H contains 9AH, indicating that this is a GRPDEF record. Bytes 01-02H contain 0008H, the length of the remainder of the record. Byte 03H contains 06H, the Group Name Index field. In this instance, the index number refers to the sixth name in the previous LNAMES record in the object module. That name is the name of the group of segments defined in the remainder of the record. Bytes 04-05H contain the first of three group component descriptor fields. Byte 04H contains the required 0FFH, indicating that the subsequent field is a segment index. Byte 05H contains 01H, a segment index that refers to the first SEGDEF record in the object module. This SEGDEF record declared the first of three segments in the group. Bytes 06-07H represent the second group component descriptor, this one referring to the second SEGDEF record in the object module. Similarly, bytes 08-09H are a group component descriptor field that references the third SEGDEF record. Byte 0AH contains the Checksum field, 55H. 9CH OR 9DH FIXUPP--FIXUP RECORD =============================== Description ----------- The FIXUPP record contains information that allows the linker to resolve (fix up) and eventually relocate references between object modules. FIXUPP records describe the LOCATION of each address value to be fixed up, the TARGET address to which the fixup refers, and the FRAME relative to which the address computation is performed. History ------- Record type 9DH is new for LINK386; it has a Target Displacement field of 32 bits rather than 16 bits, and the Location field of the Locat word has been extended to 4 bits (using the previously unused higher order S bit) to allow new LOCATION values of 9, 11, and 13. Record Format ------------- 1 2 <------from Record Length-----> 1 9C Record THREAD subrecord or Checksum or 9D Length FIXUP subrecord <--------repeated-------------> Each subrecord in a FIXUPP object record either defines a thread for subsequent use, or refers to a data location in the nearest previous LEDATA or LIDATA record. The high-order bit of the subrecord determines the subrecord type: if the high-order bit is 0, the subrecord is a THREAD subrecord; if the high-order bit is 1, the subrecord is a FIXUP subrecord. Subrecords of different types can be mixed within one object record. Information that determines how to resolve a reference can be specified explicitly in a FIXUP subrecord, or it can be specified within a FIXUP subrecord by a reference to a previous THREAD subrecord. A THREAD subrecord describes only the method to be used by the linker to refer to a particular target or frame. Because the same THREAD subrecord can be referenced in several subsequent FIXUP subrecords, a FIXUPP object record that uses THREAD subrecords may be smaller than one in which THREAD subrecords are not used. THREAD subrecords can be referenced in the same object record in which they appear and also in subsequent FIXUPP object records. THREAD Subrecord ---------------- There are four FRAME threads and four TARGET threads; not all need be defined, and they can be redefined by later THREAD subrecords in the same or later FIXUPP object records. The FRAME threads are used to specify the Frame Datum field in a later FIXUP subrecord; the TARGET threads are used to specify the Target Datum field in a later FIXUP subrecord. A THREAD subrecord does not require that a previous LEDATA or LIDATA record occur. The layout of the THREAD subrecord is as follows: <--------------1 byte--------------------> <---1 or 2 bytes---> 0 D 0 Method Thred Index 1 1 1 3 2 (bits) <---conditional----> where: 0 The high-order bit is 0 to indicate that this is a THREAD subrecord. D Is 0 for a TARGET thread, 1 for a FRAME thread. Method Is a 3-bit field. For TARGET threads, only the lower two bits of the field are used; the high-order bit of the method is derived from the P bit in the Fix Data field of FIXUP subrecords that refer to this thread. (The full list of methods is given here for completeness.) This field determines the kind of index required to specify the Target Datum field. T0 Specified by a SEGDEF index. T1 Specified by a GRPDEF index. T2 Specified by a EXTDEF index. T3 Specified by an explicit frame number (not supported by LINK). T4 Specified by a SEGDEF index only; the displacement in the FIXUP subrecord is assumed to be 0. T5 Specified by a GRPDEF index only; the displacement in the FIXUP subrecord is assumed to be 0. T6 Specified by a EXTDEF index only; the displacement in the FIXUP subrecord is assumed to be 0. The index type specified by the TARGET thread method is encoded in the Index field. For FRAME threads, the Method field determines the Frame Datum field of subsequent FIXUP subrecords that refer to this thread. Values for the Method field are: F0 The FRAME is specified by a SEGDEF index. F1 The FRAME is specified by a GRPDEF index. F2 The FRAME is specified by a EXTDEF index. LINK determines the FRAME from the external name's corresponding PUBDEF record in another object module, which specifies either a logical segment or a group. F3 Invalid. (The FRAME is identified by an explicit frame number; this is not supported by LINK.) F4 The FRAME is determined by the segment index of the previous LEDATA or LIDATA record (that is, the segment in which the location is defined). F5 The FRAME is determined by the TARGET's segment, group, or external index. F6 Invalid. NOTE: The Index field is present for FRAME methods F0, F1, and F2 only. Thred A 2-bit field that determines the thread number (0 through 3, for the four threads of each kind). Index A conditional field that contains an index value that refers to a previous SEGDEF, GRPDEF, or EXTDEF record. The field is present only if the thread method is 0, 1, or 2. (If method 3 were supported by LINK, the Index field would contain an explicit frame number.) FIXUP Subrecord --------------- A FIXUP subrecord gives the how/what/why/where/who information required to resolve or relocate a reference when program segments are combined or placed within logical segments. It applies to the nearest previous LEDATA or LIDATA record, which must be defined before the FIXUP subrecord. The FIXUP subrecord is as follows 2 1 1 or 2 1 or 2 2 or 4 Locat Fix Frame Target Target Data Datum Datum Displacement where the Locat field has an unusual format. Contrary to the usual byte order in Intel data structures, the most significant bits of the Locat field are found in the low-order, rather than the high-order, byte <-----low-order byte----><----high-order byte---> 1 M Location Data Record Offset 1 1 4 10 (bits) where: 1 The high-order bit of the low-order byte is set to indicate a FIXUP subrecord. M Is the mode; M=1 for segment-relative fixups, and M=0 for self-relative fixups. Location Is a 4-bit field that determines what type of LOCATION is to be fixed up: 0 Low-order byte (8-bit displacement or low byte of 16-bit offset). 1 16-bit offset. 2 16-bit base--logical segment base (selector). 3 32-bit Long pointer (16-bit base:16-bit offset). 4 High-order byte (high byte of 16-bit offset). LINK does not support this type. 5 16-bit loader-resolved offset, treated as Location=1 by the linker. Conflict: The PharLap OMF uses Location=5 to indicate a 32-bit offset, whereas Microsoft uses Location=9. 6 Not defined, reserved. Conflict: The PharLap OMF uses Location=6 to indicate a 48-bit pointer (16-bit base:32-bit offset), whereas Microsoft uses Location=11. 7 Not defined, reserved. 9 32-bit offset. 11 48-bit pointer (16-bit base:32-bit offset). 13 32-bit loader-resolved offset, treated as Location=9 by the linker. Data Indicates the position of the LOCATION to be fixed up Record in the LEDATA or LIDATA record immediately preceding Offset the FIXUPP record. This offset indicates either a byte in the Data Bytes field of an LEDATA record or a data byte in the Content field of a Data Block field in an LIDATA record. The Fix Data bit layout is F Frame T P Targt 1 3 1 1 2 (bits) and is interpreted as follows: F If F=1, the FRAME is given by a FRAME thread whose number is in the Frame field (modulo 4). There is no Frame Datum field in the subrecord. If F=0, the FRAME method (in the range F0 to F5) is explicitly defined in this FIXUP subrecord. The method is stored in the Frame field. Frame A 3-bit numeric field, interpreted according to the F bit. The Frame Datum field is present and is an index field for FRAME methods F0, F1, and F2 only. T If T=1, the TARGET is defined by a TARGET thread whose thread number is given in the 2-bit Targt field. The Targt field contains a number between 0 and 3 that refers to a previous THREAD subrecord containing the TARGET method. The P bit, combined with the two low- order bits of the Method field in the THREAD subrecord, determines the TARGET method. If T=0, the TARGET is specified explicitly in this FIXUP subrecord. In this case, the P bit and the Targt field can be considered a 3-bit field analogous to the Frame field. P Determines whether the Target Displacement field is present. If P=1, there is no Target Displacement field. If P=0, the Target Displacement field is present. It is a 4-byte field if the record type is 9DH; it is a 2-byte field otherwise. Targt A 2-bit numeric field, which gives the lower two bits of the TARGET method (if T=0) or gives the TARGET thread number (if T=1). Frame Datum, Target Datum, and Target Displacement Fields --------------------------------------------------------- The Frame Datum field is an index field that refers to a previous SEGDEF, GRPDEF, or EXTDEF record, depending on the FRAME method. Similarly, the Target Datum field contains a segment index, a group index, or an external name index, depending on the TARGET method. The Target Displacement field, a 16-bit or 32-bit field, is present only if the P bit in the Fix Data field is set to 0, in which case the Target Displacement field contains the offset used in methods 0, 1, and 2 of specifying a TARGET. NOTES FIXUPP records are used to fix references in the immediately preceding LEDATA, LIDATA, or COMDAT record. The Frame field is the translator's way of telling the linker the contents of the segment register used for the reference; the TARGET is the item being referenced whose address was not completely resolved by the translator. In protected mode, the only legal segment register values are selectors; every segment and group of segments is mapped through some selector and addressed by an offset within the underlying memory defined by that selector. Examples -------- Due to the incredible length of the FIXUPP examples in "The MS-DOS Encyclopedia," they are not repeated here. However, the examples are highly recommended if you want to understand what is happening. ********** Document 5 ********** A0H OR A1H LEDATA--LOGICAL ENUMERATED DATA RECORD ================================================= Description ----------- This record provides contiguous binary data--executable code or program data--that is part of a program segment. The data is eventually copied into the program's executable binary image by the linker. The data bytes may be subject to relocation or fixing up as determined by the presence of a subsequent FIXUPP record, but otherwise they require no expansion when mapped to memory at run time. History ------- Record type A1H is new for LINK386; it has an Enumerated Data Offset field of 32 bits rather than 16 bits. Record Format ------------- 1 2 1 or 2 2 or 4 1 A0 Record Segment Enumerated Data Checksum or A1 Length Index Data Bytes Offset Segment Index Field ------------------- The Segment Index field must be nonzero and is the index of a previously defined SEGDEF record. This is the segment into which the data in this LEDATA record is to be placed. Enumerated Data Offset Field ---------------------------- The Enumerated Data Offset field is either a 2- or 4-byte field (depending on the record type) that determines the offset at which the first data byte is to be placed relative to the start of the SEGDEF segment. Successive data bytes occupy successively higher locations. Data Bytes Field ---------------- The maximum number of data bytes is 1024, so that a FIXUPP Location field, which is 10 bits, can reference any of these data bytes. The number of data bytes is computed from the Record Length field minus 5, minus the size of the Segment Index field (1 or 2 bytes). NOTES Record type A1H has the offset stored as a 32-bit value. Record type A0H encodes the offset value as a 16-bit numeric field (zero- extended if applied to a Use32 segment). If an LEDATA record requires a fixup, a FIXUPP record must immediately follow the LEDATA record. Code for functions is output in LEDATA records currently. The segment for code is usually named _TEXT (or module_TEXT, depending on the memory model), unless #pragma alloc_text is used to specify a different code segment for the specified functions. For instantiated functions in C++, code will simply be output in COMDAT records that refer to the function and identify the function's segment. Data, usually generated by initialized variables (global or static), is output in LEDATA/LIDATA records referring to either a data segment or, possibly, a segment created for a based variable. Examples -------- The following LEDATA record contains a simple text string: 0 1 2 3 4 5 6 7 8 9 A B C D E F 0000 A0 13 00 02 00 00 48 65 6C 6C 6F 2C 20 77 6F 72......Hello, wor 0010 6C 64 0D 0A 24 A8 ld..$. Byte 00H contains 0A0H, which identifies this as an LEDATA record. Bytes 01-02H contain 0013H, the length of the remainder of the record. Byte 03H (the Segment Index field) contains 02H, a reference to the second SEGDEF record in the object module. Bytes 04-05H (the Enumerated Data Offset field) contain 0000H. This is the offset, from the base of the segment indicated by the Segment Index field, at which the data in the Data Bytes field will be placed when the program is linked. Of course, this offset is subject to relocation by the linker because the segment declared in the specified SEGDEF record may be relocatable and may be combined with other segments declared in other object modules. Bytes 06-14H (the Data Bytes field) contain the actual data. Byte 15H contains the Checksum field, 0A8H. A2H OR A3H LIDATA--LOGICAL ITERATED DATA RECORD =============================================== Description ----------- Like the LEDATA record, the LIDATA record contains binary data-- executable code or program data. The data in an LIDATA record, however, is specified as a repeating pattern (iterated), rather than by explicit enumeration. The data in an LIDATA record can be modified by the linker if the LIDATA record is followed by a FIXUPP record, although this is not recommended. History ------- Record type A3H is new for LINK386; it has Iterated Data Offset and Repeat Count fields of 32 bits rather than 16 bits. Record Format ------------- 1 2 1 or 2 2 or 4 1 A2 Record Segment Iterated Data Checksum or Length Index Data Block A3 Offset <-----------repeated-----------> Segment Index and Interated Data Offset Fields ---------------------------------------------- The Segment Index and Iterated Data Offset fields (2 or 4 bytes) are the same as for an LEDATA record. The index must be nonzero. This indicates the segment and offset at which the data in this LIDATA record is to be placed when the program is loaded. Data Block Field ---------------- The data blocks have the following form: 2 or 4 2 Repeat Block Content Count Count Repeat Count Field ------------------ The Repeat Count field is a 16-bit or 32-bit value that determines the number of times the Content field is to be repeated. The Repeat Count field is 32 bits only if the record type is A3H. Conflict: The PharLap OMF uses a 16-bit Repeat Count field, even in 32-bit records. Block Count Field ----------------- The Block Count field is a 16-bit word whose value determines the interpretation of the Content field, as follows: 0 Indicates that the Content field that follows is a 1-byte count value followed by count data bytes. The data bytes will be mapped to memory, repeated as many times as are specified in the Repeat Count field. != 0 Indicates that the Content field that follows is composed of one or more Data Block fields. The value in the Block Count field specifies the number of Data Block fields (recursive definition). NOTES The Microsoft C Compiler generates LIDATA records for initialized data. For example: static int a[100] = { 1, }; A FIXUPP record may occur after the LIDATA record; however, the fixup is applied before the iterated data block is expanded. It is a translator error for a fixup to reference any of the Count fields. Example 1 --------- 02 00 02 00 03 00 00 00 02 40 41 02 00 00 00 02 50 51 is an iterated data block with 16-bit repeat counts that expands to: 40 41 40 41 40 41 50 51 50 51 40 41 40 41 40 41 50 51 50 51 Here, the outer data block has a repeat count of 2 and a block count of 2 (which means to repeat twice the result of expanding the two inner data blocks). The first inner data block has repeat count = 3, block count = 0. The content is 2 bytes of data (40 41); the repeat count expands the data to a string of 6 bytes. The second (and last) inner data block has a repeat count = 2, block count = 0, content 2 bytes of data (50 51). This expands to 4 bytes, which is concatenated with the 6 bytes from the first inner data block. The resulting 10 bytes are then expanded by 2 (the repeat count of the outer data block) to form the 20-byte sequence illustrated. Example 2 --------- This sample LIDATA record corresponds to the following assembler statement, which declares a 10-element array containing the strings ALPHA and BETA: db 10 dup('ALPHA','BETA') The LIDATA record is 0 1 2 3 4 5 6 7 8 9 A B C D E F 0000 A2 1B 00 01 00 00 0A 00 02 00 01 00 00 00 05 41 ...............A 0010 4C 50 48 41 01 00 00 00 04 42 45 54 41 A9 LPHA.....BETA. Byte 00H contains 0A2H, identifying this as an LIDATA record. Bytes 01-02H contain 1BH, the length of the remainder of the record. Byte 03H (the Segment Index field) contains 01H, a reference to the first SEGDEF record in this object module, indicating that the data declared in this LIDATA record is to be placed into the segment described by the first SEGDEF record. Bytes 04-05H (the Iterated Data Offset field) contain 0000H, so the data in this LIDATA record is to be located at offset 0000H in the segment designated by the segment. Bytes 06-1CH represent an iterated data block: - Bytes 06-07H contain the repeat count, 000AH, which indicates that the Content field of this iterated data block is to be repeated 10 times. - Bytes 08-09H (the block count for this iterated data block) contain 0002H, which indicates that the Content field of this iterated data block (bytes 0A-1CH) contains two nested iterated data block fields (bytes 0A-13H and bytes 14-1CH). - Bytes 0A-0BH contain 0001H, the repeat count for the first nested iterated data block. Bytes 0C-0DH contain 0000H, indicating that the Content field of this nested iterated data block contains data rather than more nested iterated data blocks. The Content field (bytes 0E-13H) contains the data; byte 0EH contains 05H, the number of subsequent data bytes; and bytes 0F-13H contain the actual data (the string ALPHA). - Bytes 14-1CH represent the second nested iterated data block, which has a format similar to that of the block in bytes 0A-13H. This second nested iterated data block represents the 4-byte string BETA. - Byte 1DH is the Checksum field, 0A9H. B0H COMDEF--COMMUNAL NAMES DEFINITION RECORD ============================================ Description ----------- The COMDEF record is a Microsoft extension to the basic set of 8086 object record types. It declares a list of one or more communal variables (uninitialized static data, or data that may match initialized static data in another compilation unit). The size of such a variable is the maximum size defined in any module naming the variable as communal or public. The placement of communal variables is determined by the data type using established conventions (noted below). History ------- The COMDEF record is recognized by versions 3.5 and later of LINK. Record Format ------------- 1 2 1 1 or 2 1 1 or 2 1 B0 Record String Communal Type Data Communal Checksum Length Length Name Index Type Length <----------------repeated------------------> Communal Name Field ------------------- The name is in string format, and the name may be null. NEAR and FAR communals from different object files are matched at bind or link time if their names agree; the variable's size is the maximum of the sizes specified (subject to some constraints, as documented below). Type Index Field ---------------- This field encodes symbol information; it is parsed as an index field (1 or 2 bytes) and is not inspected by current linkers. This field is now used by CodeView instead of for its original purpose. Data Type and Communal Length Fields The Data Type field indicates the contents of the Communal Length field. All Data Type values for NEAR data indicate that the Communal Length field has only one numeric value: the amount of memory to be allocated for the communal variable. All Data Type values for FAR data indicate that the Communal Length field has two numeric values: the first is the number of elements, and the second is the element size. The Data Type field is one of the following hexadecimal values: 61H FAR data; the length is specified as the number of the elements followed by the element size in bytes 62H NEAR data; the length is specified as the number of bytes The Communal Length field is a single numeric field or a pair of numeric fields (as specified by the Data Type field), encoded as follows: Number Value Range of Bytes Allocation ---------------------------------------------------------------- 0 through 128 1 This byte contains the value 0 to 64K-1 3 First byte is 81H, followed by a 16-bit word whose value is used 0 to 16 MB-1 4 First byte is 84H, followed by a 3-byte value -2 GB-1 to 2 GB-1 5 First byte is 88H, followed by a 4-byte value Groups of Communal Name, Type Index, Data Type, and Communal Length fields can be repeated so that more than one communal variable can be declared in the same COMDEF record. NOTES If a public or exported symbol with the same name is found in another module to which this module is bound or linked, LINK gives the error "symbol defined more than once." Communal variables cannot be resolved to dynamic links (that is, imported symbols). The records are ordered by occurrence, together with the items named in EXTDEF and LEXTDEF records (for reference in FIXUP subrecords). In older versions of the linker, any object module that contains COMDEF records is required to also contain one COMENT record with the comment class 0A1H, indicating that Microsoft extensions to the Intel object record specification are included in the object module. This COMENT record is no longer required; current versions of the linker always interpret COMDEF records. Examples -------- The following COMDEF record was generated by Microsoft C Compiler version 4.0 for these public variable declarations: int var; /* 2-byte integer */ char var2[32768]; /* 32768-byte array */ char far var3[10][2][20]; /* 400-byte array */ The COMDEF record is: 0 1 2 3 4 5 6 7 8 9 A B C D E F 0000 B0 20 00 04 5F 66 6F 6F 00 62 02 05 5F 66 6F 6F . .._var.b.._var 0010 32 00 62 81 00 80 05 5F 66 6F 6F 33 00 61 81 90 2.b...._var3.a.. 0020 01 01 99 ... Byte 00H contains 0B0H, indicating that this is a COMDEF record. Bytes 01-02H contain 0020H, the length of the remainder of the record. Bytes 03-0AH, 0B-15H, and 16-21H represent three declarations for the communal variables var, var2, and var3. The C compiler prepends an underscore to each of the names declared in the source code, so the symbols represented in this COMDEF record are _var, _var2, and _var3. Byte 03H contains 04H, the length of the first Communal Name field in this record. Bytes 04-07H contain the name itself (_var). Byte 08H (the Type Index field) contains 00H, as required. Byte 09H (the Data Type field) contains 62H, indicating that this is a NEAR variable. Byte 0AH (the Communal Length field) contains 02H, the size of the variable in bytes. Byte 0BH contains 05H, the length of the second Communal Name field. Bytes 0C-10H contain the name _var2. Byte 11H is the Type Index field, which again contains 00H, as required. Byte 12H (the Data Type field) contains 62H, indicating that _var2 is a NEAR variable. Bytes 13-15H (the Communal Length field) contain the size in bytes of the variable. The first byte of the Communal Length field (byte 13H) is 81H, indicating that the size is represented in the subsequent two bytes of data--bytes 14-15H, which contain the value 8000H. Bytes 16-1BH represent the Communal Name field for _var3, the third communal variable declared in this record. Byte 1CH (the Type Index field) again contains 00H as required. Byte 1DH (the Data Type field) contains 61H, indicating that this is a FAR variable. This means the Communal Length field is formatted as a Number of Elements field (bytes 1E-20H, which contain the value 0190H) and an Element Size field (byte 21H, which contains 01H). The total size of this communal variable is thus 190H times 1, or 400 bytes. Byte 22H contains the Checksum field, 99H. B2H OR B3H BAKPAT--BACKPATCH RECORD =================================== Description ----------- This record is for backpatches to LOCATIONs that cannot be conveniently handled by a FIXUPP record at reference time (for example, forward references in a one-pass compiler). It is essentially a specialized fixup. History ------- Record type B2H is a Microsoft extension that was added for QuickC version 1.0. Record type B3H is the 32-bit equivalent: the Offset and Value fields are 32 bits rather than 16 bits. Record Format ------------- 1 2 1 or 2 1 2 or 4 2 or 4 1 B2 Record Segment Location Offset Value Checksum or B3 Length Index Type <-----repeated-----> Segment Index Field ------------------- Segment index to which all "backpatch" FIXUPP records are to be applied. Note that, in contrast to FIXUPP records, these records do not need to follow the data record to be fixed up. Hence, the segment to which the backpatch applies must be specified explicitly. Location Type Field ------------------- Type of LOCATION to be patched; the only valid values are: 0 8-bit low-order byte 1 16-bit offset 2 32-bit offset, record type B3H only (not supported yet) Offset and Value Fields ----------------------- These fields are 32 bits for record type B3H, and 16 bits for B2H. The Offset field specifies the LOCATION to be patched (as an offset into the SEGDEF record whose index is Segment Index). The associated Value field is added to the LOCATION being patched (unsigned addition, ignoring overflow). The Value field is a fixed length (16 bits or 32 bits, depending on the record type) to make object-module processing easier. NOTE: BAKPAT records can occur anywhere in the object module following the SEGDEF record to which they refer. They do not have to immediately follow the appropriate LEDATA record as FIXUPP records do. These records are buffered by the linker in Pass 2 until the end of the module, after the linker applies all other FIXUPP records. LINK then processes these records as fixups. Examples -------- For example, to generate a self-relative address whose TARGET is a forward reference (JZ forwardlabel), the translator can insert the negative offset of the next instruction (-*) from the start of the SEGDEF record, followed by an additive backpatch (meaning that the backpatch is added to the original value and the sum replaces the original value) whose Value is the offset of the TARGET of the jump, which is done last. B4H OR B5H LEXTDEF--LOCAL EXTERNAL NAMES DEFINITION RECORD ========================================================== Description ----------- This record is identical in form to the EXTDEF record described earlier. However, the symbols named in this record are not visible outside the module in which they are defined. History ------- This record was a Microsoft extension for C 5.0. There is no semantic difference between the B4H and B5H types. Record Format ------------- 1 2 1 1 or 2 1 B4 Record String External Type Checksum B5 Length Length Name String Index <--------------repeated-------> NOTE: These records are associated with LPUBDEF and LCOMDEF records and ordered with the EXTDEF records by occurrence, so that they may be referenced by an external name index for fixups. The name string, when stored in LINK's internal data structures, is encoded with spaces and digits at the beginning of the name. Examples -------- This record type is produced in C from static functions, such as: static int var() { } B6H OR B7H LPUBDEF--LOCAL PUBLIC NAMES DEFINITION RECORD ======================================================== Description ----------- This record is identical in form to the PUBDEF record described earlier. However, the symbols named in this record are not visible outside the module in which they are defined. History ------- This record was a Microsoft extension for C 5.0. Record type B7H is new for LINK386: the Local Offset field is 32 bits rather than 16 bits. Record Format ------------- 1 2 1 or 2 1 or 2 2 1 B6 Record Base Base Base String Local Local Type Checksum or Length Group Segment Frame Length Name Offset Index B7 String <----------repeated----------> Examples -------- In C, the static keyword on functions or initialized variables produces LPUBDEF records. Uninitialized static variables produce LCOMDEF records. B8H LCOMDEF--LOCAL COMMUNAL NAMES DEFINITION RECORD =================================================== Description ----------- This record is identical in form to the COMDEF record described previously. However, the symbols named in this record are not visible outside the module in which they are defined. History ------- This record was a Microsoft extension for C 5.0. Record Format ------------- 1 2 1 or 2 Data Type> B8 Record String Communal Type Data Communal Checksum Length Length Name Index Type Length <--------------repeated----------------------> Examples -------- In C, uninitialized static variables produce an LCOMDEF record. BCH CEXTDEF--COMDAT EXTERNAL NAMES DEFINITION RECORD ==================================================== Description ----------- This record serves the same purpose as the EXTDEF record described earlier. However, the symbol named is referred to through a Logical Name Index field. Such a Logical Name Index field is defined through an LNAMES or LLNAMES record. History ------- The record is a Microsoft extension for C 7.0. Record Format ------------- 1 2 1 or 2 1 or 2 1 BC Record Logical Name Type Checksum Length Index Index <---------repeated--------> NOTE: A CEXTDEF can precede the COMDAT to which it will be resolved. In this case, the location of the COMDAT is not known at the time the CEXTDEF is seen. Examples -------- This record is produced when a FIXUPP record refers to a COMDAT symbol. C2H OR C3H COMDAT--INITIALIZED COMMUNAL DATA RECORD =================================================== Description ----------- The purpose of the COMDAT record is to combine logical blocks of code and data that may be duplicated across a number of compiled modules. History ------- The record is a Microsoft extension for C 7.0. Record Format ------------- 1 2 1 1 1 2 or 4 1 or 2 1 or 2 1 1 C2 Record Flags Attrib Align Enumer Type Public Public Data Check or Length -utes -ated Index Base Name Sum C3 Data Index Offset Flags Field ----------- This field contains the following defined bits: 01H Continuation bit. If clear, this COMDAT record establishes a new instance of the COMDAT variable; otherwise, the data is a continuation of the previous COMDAT of the symbol. 02H Iterated data bit. If clear, the Data field contains enumerated data; otherwise, the Data field contains iterated data, as in an LIDATA record. 04H Local bit (effectively an "LCOMDAT"). This is used in preference to LLNAMES. 08H Data in code segment. If the application is overlayed, this COMDAT must be forced into the root text. Also, do not apply FARCALLTRANSLATION to this COMDAT. Attributes Field ---------------- This field contains two 4-bit fields: the Selection Criteria to be used, and the Allocation Type, an ordinal specifying the type of allocation to be performed. Values are: Selection Criteria (High-Order 4 Bits): Bit Selection Criteria 00H No match Only one instance of this COMDAT allowed. 10H Pick Any Pick any instance of this COMDAT. 20H Same Pick any instance, but instances must have Size the same length or the linker will generate an error. 30H Exact Pick any instance, but checksums of the Match instances must match or the linker will generate an error. Fixups are ignored. 40H - Reserved. F0H Allocation Type (Low-Order 4 bits): Bit Allocation 00H Explicit Allocate in the segment specified in the ensuing Base Group, Base Segment, and Base Frame fields. 01H Far Allocate as CODE16. The linker will create Code segments to contain all COMDATs of this type. 02H Far Allocate as DATA16. The linker will create Data segments to contain all COMDATs of this type. 03H Code32 Allocate as CODE32. The linker will create segments to contain all COMDATs of this type. 04H Data32 Allocate as DATA32. The linker will create segments to contain all COMDATs of this type. 05H - Reserved. 0FH Align Field These codes are based on the ones used by the SEGDEF record: 0 Use value from SEGDEF 1 Byte aligned 2 Word aligned 3 Paragraph (16 byte) aligned 4 256-byte aligned 5 Double word (4 byte) aligned 6 Not defined 7 Not defined Enumerated Data Offset Field ---------------------------- This field specifies an offset relative to the beginning location of the symbol specified in the Public Name Index field and defines the relative location of the first byte of the Data field. Successive data bytes in the Data field occupy higher locations of memory. This works very much like the Enumerated Data Offset field in an LEDATA record, but instead of an offset relative to a segment, this is relative to the beginning of the COMDAT symbol. Type Index Field ---------------- The Type Index field is encoded in index format; it contains either proprietary CodeView-type information or an old-style TYPDEF index. If this index is 0, there is no associated type data. Old-style TYPDEF indexes are ignored by LINK. Current linkers do not perform type checking. Public Base Field ----------------- This field is conditional and is identical to the public base fields (Base Group, Base Segment, and Base Frame) stored in the PUBDEF record. This field is present only if the Allocation Type field specifies Explicit allocation. Public Name Index Field ----------------------- This field is a regular logical name index (1 or 2 bytes). Data Field ---------- The Data field provides up to 1024 consecutive bytes of data. If there are fixups, they must be emitted in a FIXUPP record that follows the COMDAT record. The data can be either enumerated or iterated, depending on the Flags field. NOTES Record type C3H has an Enumerated Data Offset field of 32 bits. While creating addressing frames, the linker will add the COMDAT data to the appropriate logical segments, adjusting their sizes. At that time, the offset at which the data will go inside the logical segment will be calculated. Next, the linker will create physical segments from adjusted logical segments, reporting any 64K boundary overflows. If the allocation type is not explicit, COMDAT code and data is accumulated by the linker and broken up into segments, so that the total can exceed 64K. In Pass 2, only the selected occurrence of COMDAT data will be stored in virtual memory, fixed up, and later written into the .EXE file. COMDATs are allocated in the order of their appearance in the .OBJ files if no explicit ordering is given. A COMDAT record cannot be continued across modules. A COMDAT record can be duplicated in a single module. If any COMDAT record on a given symbol has the local bit set, all the COMDAT records on that symbol have that bit set. ********** Document 6 ********** C4H OR C5H LINSYM--SYMBOL LINE NUMBERS RECORD ============================================= Description ----------- This record will be used to output line numbers for functions specified through COMDAT records. Each LINSYM record is associated with a preceding COMDAT record. History ------- This record is a Microsoft extension for C 7.0. Record Format ------------- 1 2 1 1 or 2 2 2 or 4 1 C4 Record Flags Public Line Line Checksum or Length Name Number Number C5 Index Offset <---repeated---> Flags Field ----------- This field contains one defined bit: 01H Continuation bit. If clear, this COMDAT record establishes a new instance of the COMDAT variable; otherwise, the data is a continuation of the previous COMDAT of the symbol. Public Name Index Field ----------------------- A regular logical name index, indicating the name of the base of the LINSYM record. Line Number Field ----------------- An unsigned number in the range 0 to 65,535. Line Number Offset Field ------------------------ The offset relative to the base specified by the symbol name base. The size of this field depends on the record type. NOTES Record type C5H is identical to C4H except that the Line Number Offset field is 4 bytes instead of 2. This record is used to output line numbers for functions specified through COMDAT records. Often, the residing segment as well as the relative offsets of such functions is unknown at compile time, in that the linker is the final arbiter of such information. For such cases, the compiler will generate this record to specify the line number/offset pairs relative to a symbolic name. This record will also be used to discard duplicate LINNUM information. If the linker encounters two or more LINSYM records with matching symbolic names (corresponding to multiple COMDAT records with the same name), the linker will keep the one that corresponds to the retained COMDAT. LINSYM records must follow the COMDATs to which they refer. A LINSYM on a given symbol refers to the most recent COMDAT on the same symbol. LINSYMs inherit the "localness" of their COMDATs. C6H ALIAS--ALIAS DEFINITION RECORD ================================== Description ----------- This record has been introduced to support link-time aliasing, a method by which compilers or assemblers may direct the linker to substitute all references to one symbol for another. History ------- The record is a Microsoft extension for FORTRAN version 5.1 (LINK version 5.13). Record Format ------------- 1 2 1 C6 Record Length Alias Name Substitute Name Checksum <-----------repeated---------> Alias Name Field ---------------- A regular length-preceded name of the alias symbol. Substitute Name Field --------------------- A regular length-preceded name of the substitute symbol. NOTES This record consists of two symbolic names: the alias symbol and the substitute symbol. The alias symbol behaves very much like a PUBDEF in that it must be unique. If a PUBDEF of an alias symbol is encountered later, the PUBDEF overrides the alias. If another ALIAS record with a different substitute symbol is encountered, a warning is emitted by the linker, and the second substitute symbol is used. When attempting to satisfy an external reference, if an ALIAS record whose alias symbol matches is found, the linker will halt the search for alias symbol definitions and will attempt to satisfy the reference with the substitute symbol. All ALIAS records must appear before the LINK Pass 2 record. C8H OR C9H NBKPAT--NAMED BACKPATCH RECORD ========================================= Description ----------- The Named Backpatch record is similar to a BAKPAT record, except that it refers to a COMDAT record, by logical name index, rather than an LIDATA or LEDATA record. NBKPAT records must immediately follow the COMDAT/FIXUPP block to which they refer. History ------- This record is a Microsoft extension for C 7.0. Record Format ------------- 1 2 1 1 or 2 2 or 4 2 or 4 1 C8 Record Location Public Offset Value Checksum or C9 Length Type Name <---repeated---> Location Type Field ------------------- Type of location to be patched; the only valid values are: 0 8-bit byte 1 16-bit word 2 32-bit double word, record type C9H only Public Name Index Field ----------------------- Regular logical name index of the COMDAT record to be back patched. Offset and Value Fields ----------------------- These fields are 32 bits for record type C8H, 16 bits for C9H. The Offset field specifies the location to be patched, as an offset into the COMDAT. The associated Value field is added to the location being patched (unsigned addition, ignoring overflow). The Value field is a fixed length (16 bits or 32 bits, depending on the record type) to make object module processing easier. CAH LLNAMES--LOCAL LOGICAL NAMES DEFINITION RECORD ================================================== Description ----------- The LLNAMES record is a list of local names that can be referenced by subsequent SEGDEF and GRPDEF records in the object module. The names are ordered by their occurrence, with the names in LNAMES records and referenced by index from subsequent records. More than one LNAMES and LLNAMES record may appear. The names themselves are used as segment, class, group, overlay, COMDAT, and selector names. History ------- This record is a Microsoft extension for C 7.0. Record Format ------------- 1 2 1 <--String Length--> 1 CA Record String Name Checksum Length Length String <----------repeated---------> Each name appears in format, and a null name is valid. The character set is ASCII. Names can be up to 254 characters long. NOTE: Any LLNAMES records in an object module must appear before the records that refer to them. APPENDIX 1: CODEVIEW EXTENSIONS =============================== Calling the following information "CodeView's OMF" is a misnomer, since CodeView actually does very little to extend the OMF. Most CodeView information is stored within the confines of the existing OMF, except where noted below. CodeView information is stored on a per-module basis in specially- named logical segments. These segments are defined in the usual way (SEGDEF records), but LINK handles them specially, and they do not end up as segments in the .EXE file. These segment names are reserved: Segment Name Class Name Combine Type ------------ ---------- ------------ $$TYPES DEBTYP Private $$SYMBOLS DEBSYM Private The segment $$IMPORT should also be considered a reserved name, although it is not used anymore. This segment was not part of any object files but was emitted by the linker to get the loader to automatically do fixups for CodeView information. The linker emitted a standard set of imports, not just ones referenced by the program being linked. Use of this segment may be revisited in the future. CodeView-specific data is stored in LEDATA records for the $$TYPES and $$SYMBOLS segments, in various proprietary formats. The $$TYPES segment contains information on user-defined variable types; $$SYMBOLS contains information about nonpublic symbols: stack, local, procedure, block start, constant, and register symbols and code labels. For instantiated functions in C 7.0, symbol information for CodeView will be output in COMDAT records that refer to segment $$SYMBOLS and have decorated names based on the function names. Type information will still go into the $$TYPES segment in LEDATA records. All OMF records that specify a Type Index field, including EXTDEF, PUBDEF, and COMDEF records, use proprietary CodeView values. Since many types are common, Type Index values in the range 0 through 511 (1FFH) are reserved for a set of predefined primitive types. Indexes in the range 512 through 32767 (200H-7FFFH) index into the set of type definitions in the module's $$TYPES segment, offset by 512. Thus 512 is the first new type, 513 the second, and so on. APPENDIX 2: MICROSOFT MS-DOS LIBRARY FORMAT =========================================== Libraries under MS-DOS are always multiples of 512-byte blocks. The first record in the library is a header. This first record looks very much like any other Microsoft object module format record. Library Header Record ( bytes) --------------------------------- 1 2 4 2 1 Type Record Length Dictionary Dictionary Flags Padding Offest Size (F0H) (Page Size Minus 3) in Blocks The first byte of the record identifies the record's type, and the next two bytes specify the number of bytes remaining in the record. Note that this word field is byte-swapped (that is, the low-order byte precedes the high-order byte). The record type for this library header is F0H (240 decimal). The Record Length field specifies the page size within the library. Modules in a library always start at the beginning of a page. Page size is determined by adding three to the value in the Record Length field (thus the header record always occupies exactly one page). Legal values for the page size are given by 2 to the , where is greater than or equal to 4 and less than or equal to 15. The four bytes immediately following the Record Length field are a byte-swapped long integer specifying the byte offset within the library of the first byte of the first block of the dictionary. The next two bytes are a byte-swapped word field that specifies the number of blocks in the dictionary. (The MS-DOS Library Manager cannot create a library whose dictionary would require more than 251 512-byte pages.) The next byte contains flags describing the library. The current flag definition is: 0x01 = case sensitive (applies to both regular and extended dictionaries) All other values are reserved for future use and should be 0. The remaining bytes in the library header record are not significant. This record deviates from the typical Microsoft OMF record in that the last byte is not used as a checksum on the rest of the record. Immediately following the header is the first object module in the library. It, in turn, is succeeded by all other object modules in the library. Each module is in Microsoft OMF (that is, it starts with a LHEADR record and ends with a MODEND record). Individual modules are aligned so as to begin at the beginning of a new page. If, as is commonly the case, a module does not occupy a number of bytes that is exactly a multiple of the page size, then its last block will be padded with as many null bytes as are required to fill it. Following the last object module in the library is a record that serves as a marker between the object modules and the dictionary. It also resembles a Microsoft OMF record. Library End Record (marks end of objects and beginning of dictionary) 1 2 Type (F1H) Record Length Padding The record's Type field contains F1H (241 decimal), and its Record Length field is set so that the dictionary begins on a 512-byte boundary. The record contains no further useful information; the remaining bytes are insignificant. As with the library header, the last byte is not a checksum. Dictionary ---------- The remaining blocks in the library compose the dictionary. The number of blocks in the dictionary is given in the library header. Note that there should always be a prime number of blocks in the dictionary. The dictionary is a hashed index to the library. Public symbols are essentially hashed twice, though in fact, both hash indexes are produced simultaneously. The first hash index, the block index, is used to determine a block within the dictionary in which to place the symbol. The second hash index, the bucket index, is used to choose a bucket within the block for the symbol. Blocks always have 37 buckets; they are the first 37 bytes of each block. If a bucket is full, it contains a nonzero value that points to the text of the symbol. To actually find the symbol, take the bucket value, multiply it by two, and use the resulting number as a byte offset from the beginning of the block. Collisions (that is, two or more distinct symbols hashing to the same block and bucket in the dictionary) are resolved by a technique known as linear open addressing. At the same time the hash indexes are produced, two hash deltas are also produced. If a symbol collides with a symbol already installed in the dictionary, the librarian attempts to find an empty bucket for it by adding the bucket delta to the bucket index and using the result mod 37 as a new bucket index. If this new bucket index points to a bucket that is empty, the librarian will install the symbol in that bucket. If the bucket is not empty, the delta is applied repeatedly until an empty bucket is found or until it is determined that there are no empty buckets on the block. If the latter is the case, the block delta is added to the block index, and the result mod the number of blocks in the dictionary is used as a new block index. With the new block index and the original bucket index, the sequence is repeated until an empty bucket on some block is found. The number of blocks and the number of buckets are prime so that no matter what values of hash indexes and deltas are produced for a symbol, in the worst case, all possible block-bucket combinations will be tried. Once a free block-bucket pair has been found for a symbol, the pair and information concerning its place of definition must be installed. Since a bucket is a single byte pointing into a 512-byte block, the bucket can give at best a word offset within that block. Thus, symbol entries within a dictionary must start on word boundaries. Since bytes 0 through 36 of each dictionary block make up the hash table, the first symbol entry will begin at byte 38 (decimal). Dictionary Record (length is the dictionary size in 512-byte blocks) 37 1 2 HTAB FFLAG Name Block Number Align Byte <-------------------repeated-------------> Entries consist of the following: the first byte is the length of the symbol to follow, the following bytes are the text of the symbol, and the last two bytes are a byte-swapped word field that specifies the page number (counting the library header as the 0th page) at which the module defining the symbol begins. All entries may have at most one trailing null byte in order to align the next entry on a word boundary. It is possible for a dictionary block to be full without all its buckets being used. Such will be the case, for example, if symbol names are longer on average than nine characters each. Therefore, there must be some way to mark a block as full so that empty buckets will be ignored. Byte 37 decimal (counting from 0) is reserved for this purpose. If the block is not full, byte 37 will contain the word offset of the beginning of free space in the block, but if the block is full, byte 37 will contain the special value 255 decimal (FFH). Module names are stored in the LHEADR record of each module. Extended Dictionary ------------------- The extended dictionary is optional and indicates dependencies between modules in the library. Versions of LIB earlier than 3.09 do not create an extended dictionary. The extended dictionary is placed at the end of the library. The dictionary is preceded by these values: BYTE =0xF2 Extended Dictionary header WORD length of extended dictionary in bytes excluding first three bytes Start of extended dictionary: WORD number of modules in library = N Module table, indexed by module number, with N + 1 fixed-length entries: WORD module page number WORD offset from start of extended dictionary to list of required modules Last entry is null. Dictionary Hashing Algorithm ---------------------------- The last part of each library file is a dictionary, which contains indexes to all symbols in the library. The dictionary is divided into 512-byte pages. Each page consists of a 37-byte bucket table and a 475- byte table of symbol entries. To find the right spot in the dictionary for a given symbol, the hashing algorithm is used. The hashing algorithm analyzes the name of the symbol and produces two indexes: a page and a bucket index, which together point to a single entry in the dictionary. The only problem is that more than one symbol name can generate exactly the same address. Because of this, the name found in the dictionary entry must be compared with the symbol's name, and if they are not identical, a correction to the address must be made. To make this correction possible, the hashing algorithm, in addition to the base address (page, bucket), also produces the correction values (delta-page, delta- bucket), which are added to the base address if the symbol's name does not match the name in an entry. The number of pages in the dictionary must always be prime, so if the symbol is not found, the consecutive adding of deltas produces the starting address again. Below is psueudocode illustrating the hashing algorithm used by the LIB (librarian) utility. extern char *symbol; /* Symbol to find */ extern int dictlength; /* Dictionary length in pages */ extern int buckets; /* Number of buckets on one page */ char *pb; /* A pointer to the beginning of the symbol */ char *pe; /* " end " */ int slength; /* Length of the symbol's name */ int page_index; /* Page index */ int page_index_delta;/* Page index delta */ int page_offset; /* Page offset (bucket #) */ int page_offset_delta;/* Page offset delta */ unsigned c; slength = strlen(symbol); pb = symbol; pe = symbol + slength; page_index = 0; page_index_delta = 0; page_offset = 0; page_offset_delta = 0; while( slength-) { c = *(pf++) | 32; /* Convert character to lowercase */ page_index = (page_index<<2) XOR c; /* Hash */ page_offset_delta = (page_offset_delta>>2)XORc; c = *(pe++) | 32; page_offset = (page_offset>>2) XOR c; /* Hash */ pageiindexdelta = (page_index_delta<<2) XOR c; } /* Calculate page index */ page_index = page_index MODULO dictlength; /* Calculate page index delta */ if((page_index_delta = page_index_delta MODULO dictlength) == 0) page_index_delta = 1; /* Calculate page offset */ page_offset = page_offset MODULO buckets; /* Calculate page offset delta */ if( (page_offset_delta = page_offset_delta MODULO buckets) == 0) page_offset_delta = 1;