* remove "\r" nonsense
[mascara-docs.git] / manuals / openwatcom / linux.port.txt
blobef346e28b584e24e42f27c88cf581d0d3346a1a6
1 Linux Port
3 From Open Watcom
5 Jump to: navigation, search
7 FIXME: This page needs updated to reflect current status, and potentially be
8 broken into smaller sections.
10 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
12 Executive summary
14 This document describes a detailed approach to porting Open Watcom Compiler and
15 Linker to Linux platform.
17 Contents
19   • 1 Introduction
20   • 2 Key Components of the Open Watcom C Compiler and Linker
21       □ 2.1 ORL
22       □ 2.2 WLCore
23       □ 2.3 Load ELF
24       □ 2.4 GC386
25       □ 2.5 OWL
26   • 3 Porting Open Watcom C Compiler and Linker to Linux
27       □ 3.1 Position-Independent Code
28           ☆ 3.1.1 Command Line Switches
29           ☆ 3.1.2 ELF Object Files
30           ☆ 3.1.3 PIC Generation
31       □ 3.2 Building Shared Objects
32           ☆ 3.2.1 Linker Command Line
33           ☆ 3.2.2 ELF Header
34           ☆ 3.2.3 Segments and Sections
35           ☆ 3.2.4 Program Headers
36           ☆ 3.2.5 Dynamic Section
37           ☆ 3.2.6 Dynamic Symbols
38           ☆ 3.2.7 Dynamic Relocations
39           ☆ 3.2.8 Global Offset Table
40           ☆ 3.2.9 Procedure Linkage Table
41       □ 3.3 Using Shared Objects
42           ☆ 3.3.1 Reading Shared Objects
43           ☆ 3.3.2 Program Interpreter
44           ☆ 3.3.3 Required Libraries
45           ☆ 3.3.4 Global Offset Table
46           ☆ 3.3.5 Procedure Linkage Table
47   • 4 Existing Problems
48   • 5 Estimation
50 [edit]
52 Introduction
54 This document outlines a set of steps that should be taken to provide shared
55 libraries and position independent code support to the Open Watcom compiler as
56 a part of the Open Watcom Linux porting effort.
58 All information is presented relative to open_watcom_devel_1.1.7. Since Open
59 Watcom is open-source project, we assume some of the topics covered might
60 become obsolete or inaccurate at the moment of reading this document. A
61 considerable amount of experimental work was performed prior writing this
62 Specification. Some results of that work are included in this document.
64 This document consists of four large sections. Section one is an introductory
65 section. Section two describes the key components of Open Watcom C Compiler and
66 Linker. Section three defines steps, needed for adding PIC and shared object
67 support. Section four describes some problems found during our investigation.
69 Definitions, acronyms and abbreviations
71 ABI - Application Binary Interface
73 ELF - Executable and Linking Format
75 There are three main types of ELF files:
77   • A relocatable file holds code and data suitable for linking with other
78     object files to create an executable or a shared object file.
79   • An executable file holds a program suitable for execution; the file
80     specifies how the function exec() creates a program’s process image.
81   • A shared object file holds code and data suitable for linking in two
82     contexts. First, the link editor may process it with other relocatable and
83     shared object files to create another object file. Second, the dynamic
84     linker combines it with an executable file and other shared objects to
85     create a process image.
87 wlink have limited support of building and using of ELF files.
89 OMF - Relocatable Object Module Format
91 This format (developed by Microsoft) is produced by wcc386 (and has “native”
92 support in wlink).
94 ORL - Object Reading Library
96 API for reading object files.
98 PDC - Position Dependent Code (opposite to PIC)
100 PIC - Position Independent Code
102 This lets a segment’s virtual address change from one process to another,
103 without invalidating execution behavior. Because PIC uses relative addressing
104 between segments, the difference between virtual addresses in memory must match
105 the difference between virtual addresses in the file. The difference between
106 the virtual address of any segment in memory and the corresponding virtual
107 address in the file is thus a single constant value for any one executable or
108 shared object in a given process.
110 wcc386 - Open Watcom C Compiler
112 wlink - Open Watcom Linker
115 References
117  1. SYSTEM V APPLICATION BINARY INTERFACE, Edition 4.1
118  2. SYSTEM V APPLICATION BINARY INTERFACE, Intel386™ Architecture Processor
119     Supplement, Fourth Edition
120  3. Linux Standard Base Specification for the IA32 Architecture 1.9.0-20031030
121  4. OMF 1.1 Specification
124 [edit]
126 Key Components of the Open Watcom C Compiler and Linker
128 Certain parts of the Open Watcom source code are especially important for our
129 project. Such parts will be referred as “components” throughout this document,
130 although some of them are logically interrelated source files, and others are
131 subprojects (subdirectories under the Open Watcom source tree). The informal
132 names defined here will be used in the further parts of this document.
134 Each component is described in two sections. First section describes the
135 purpose of the component, and provides the list of core source files. Second
136 section describes the principles of function of the corresponding component.
137 Important functions, data structures, and constants are described as well.
139 [edit]
143 Definition
145 Abbreviation of “Object Reading Library”. Located in $OWROOT/bld/orl.
147 ORL is designed for reading various formats of object files: ELF, OMF, and
148 COFF. We are interested mainly in the ELF stuff ($OWROOT/bld/orl/elf).
150 ELF linking information (e.g. relocation entries) is mapped to abstract ORL
151 linking information. For example, ELF relocation type R_386_32 is mapped to
152 ORL_RELOC_TYPE_WORD_32.
154 Description
156 There are several handle types defined in ORL. Most important are
157 orl_sec_handle and orl_symbol_handle. There are many functions operating with
158 sections and symbols:
160 char * ORLSecGetName( orl_sec_handle );
162 orl_sec_offset ORLSecGetBase( orl_sec_handle );
164 orl_sec_size ORLSecGetSize( orl_sec_handle );
166 orl_sec_type ORLSecGetType( orl_sec_handle );
168 orl_sec_flags ORLSecGetFlags( orl_sec_handle );
170 orl_sec_alignment ORLSecGetAlignment( orl_sec_handle );
172 orl_sec_handle ORLSecGetStringTable( orl_sec_handle );
174 orl_sec_handle ORLSecGetSymbolTable( orl_sec_handle );
176 orl_sec_handle ORLSecGetRelocTable( orl_sec_handle );
178 orl_linnum * ORLSecGetLines( orl_sec_handle );
180 orl_table_index ORLSecGetNumLines( orl_sec_handle );
182 orl_sec_offset ORLSecGetOffset( orl_sec_handle );
184 orl_return ORLSecGetContents( orl_sec_handle, char ** );
186 orl_return ORLSecQueryReloc( orl_sec_handle, orl_sec_offset, orl_reloc_return_func );
188 orl_return ORLSecScanReloc( orl_sec_handle, orl_reloc_return_func );
190 orl_table_index ORLCvtSecHdlToIdx( orl_sec_handle );
192 orl_sec_handle ORLCvtIdxToSecHdl( orl_file_handle, orl_table_index );
194 char * ORLSecGetClassName( orl_sec_handle );
196 orl_sec_combine ORLSecGetCombine( orl_sec_handle );
198 orl_sec_frame ORLSecGetAbsFrame( orl_sec_handle );
200 orl_sec_handle ORLSecGetAssociated( orl_sec_handle );
202 orl_group_handle ORLSecGetGroup( orl_sec_handle );
204 orl_return ORLRelocSecScan( orl_sec_handle, orl_reloc_return_func );
206 orl_return ORLSymbolSecScan( orl_sec_handle, orl_symbol_return_func );
208 orl_return ORLNoteSecScan( orl_sec_handle, orl_note_callbacks *, void * );
210 char * ORLSymbolGetName( orl_symbol_handle );
212 orl_symbol_value ORLSymbolGetValue( orl_symbol_handle );
214 orl_symbol_binding ORLSymbolGetBinding( orl_symbol_handle );
216 orl_symbol_type ORLSymbolGetType( orl_symbol_handle );
218 unsigned char ORLSymbolGetRawInfo( orl_symbol_handle );
220 orl_sec_handle ORLSymbolGetSecHandle( orl_symbol_handle );
222 orl_symbol_handle ORLSymbolGetAssociated( orl_symbol_handle );
224 These and other functions allow access to the object file in the uniform way.
225 Actual mapping from ELF to ORL is performed by $OWROOT/bld/orl/elf/c/elfentr.c
226 (sections, symbols), elfload.c (sections), elflwlv.c (symbols, relocations).
228 ORL is used by Open Watcom Linker, mostly in $OWROOT/bld/wl/c/objorl.c.
230 ELF relocations (i.e. 386 ABI) are mapped to abstract ORL relocations in the
231 following way:
233 $OWROOT/bld/orl/elf/c/elflwlv.c
235 static orl_reloc_type convert386Reloc( elf_reloc_type elf_type ) {
236   switch( elf_type ) {
237     case R_386_NONE:
238          return( ORL_RELOC_TYPE_ABSOLUTE );
239     case R_386_32:
240     case R_386_GOT32:
241     case R_386_GOTOFF:
242          return( ORL_RELOC_TYPE_WORD_32 );
243     case R_386_PC32:
244     case R_386_PLT32:
245     case R_386_GOTPC:
246          return( ORL_RELOC_TYPE_REL_32 );
247     default:
248          assert( 0 );
249   }
250   return( ORL_RELOC_TYPE_NONE );
253 [edit]
255 WLCore
257 Definition
259 Synthetically selected part of the Open Watcom Linker ($OWROOT/bld/wl),
260 performing the basic linking tasks (e.g. relocations), and interacting to ORL.
261 Main files: obj2supp.c, objcalc.c, objorl.c, objpass1.c, objpass2.c.
263 Description
265 We are interested mainly in ELF linking. Since ORL is used to read ELF object
266 files, there is an interface to ORL implemented in objorl.c. The linker uses
267 other data structures than ORL, so there is another mapping implemented in the
268 mentioned file. Relocations are mapped in the following way:
270 switch( reloc->type ) {
271   // ...
272   case ORL_RELOC_TYPE_ABSOLUTE:
273        type = FIX_OFFSET_32 | FIX_ABS;
274        break;
275   // ...
276   case ORL_RELOC_TYPE_REL_32:
277        type = FIX_OFFSET_32 | FIX_REL;
278        break;
279   // ...
280   case ORL_RELOC_TYPE_WORD_32:
281        type = FIX_OFFSET_32;
282        break;
283   }
285 Constants FIX_ are defined in the spirit of OMF specification (i.e. FIXUPP
286 records). However, some of these constants implement specific features, e.g.
287 PowerPC relocations.
289 $OWROOT/bld/wl/h/obj2supp.h
291 typedef enum {
292   FIX_CHANGE_SEG = 0x00000001, // has to be 1. used in pointers!
293   FIX_ADDEND_ZERO = 0x00000002,
294   FIX_UNSAFE = 0x00000004,
295   FIX_ABS = 0x00000008,
296   FIX_BASE = 0x00000010,
297   FIX_HIGH = 0x00000020,
298   FIX_REL = 0x00000040,
299   FIX_SHIFT = 0x00000080,
300   FIX_TARGET_SHIFT = 8, // contains frame_type
301   FIX_TARGET_MASK = 0x00000700,
302   FIX_NO_BASE = 0x00001000,
303   FIX_SIGNED = 0x00002000,
304   FIX_LOADER_RES = 0x00004000,
305   FIX_SEC_REL = 0x00008000,
306   FIX_NO_OFFSET = 0,
307   FIX_OFFSET_8 = 0x00010000,
308   FIX_OFFSET_16 = 0x00020000,
309   FIX_OFFSET_21 = 0x00030000,
310   FIX_OFFSET_32 = 0x00040000,
311   FIX_OFFSET_24 = 0x00050000,
312   FIX_OFFSET_SHIFT = 16,
313   FIX_OFFSET_MASK = 0x00070000,
314   FIX_TOC = 0x00100000, // PPC PE
315   FIX_TOCV = 0x00200000, // PPC PE
316   FIX_IFGLUE = 0x00300000, // PPC PE
317   FIX_SPECIAL_MASK = 0x00300000,
318   FIX_FRAME_SHIFT = 24, // contains frame_type
319   FIX_FRAME_MASK = 0x07000000,
320   // now for some handy constants which use these
321   FIX_BASE_OFFSET_16 = (FIX_BASE | FIX_OFFSET_16),
322   FIX_BASE_OFFSET_32 = (FIX_BASE | FIX_OFFSET_32),
323   FIX_HIGH_OFFSET_8 = (FIX_HIGH | FIX_OFFSET_8),
324   FIX_HIGH_OFFSET_16 = (FIX_HIGH | FIX_OFFSET_16),
325 } fix_type;
327 During the first pass, relocations are converted to internal representation:
329 $OWROOT/bld/wl/c/objorl.c
331 static orl_return P1Relocs( orl_sec_handle sec ) {
332   return ORLRelocSecScan( sec, DoReloc );
335 Here ORLRelocSecScan is ORL-function that iterates through the relocation list,
336 and DoReloc() is called to convert each relocation (see above).
338 Relocation processing is actually implemented in obj2supp.c. This file is a key
339 part of the linker.
341 Other important participants of linking process are symbols. Like relocations,
342 ELF symbols (accessible through ORL functions) are converted to the internal
343 symbol structures:
345 $OWROOT/bld/wl/h/syms.h
347 typedef struct symbol {
348   struct symbol * hash;
349   struct symbol * publink;
350   struct symbol * link;
351   targ_addr addr;
352   unsigned_16 namelen;
353   sym_info info;             // flags & floating point fixup type.
354   struct mod_entry * mod;
355   union {
356     void * edges;            // for dead code elim. when sym undefd
357     struct segdata *seg;     // seg symbol is in.
358     char * alias;            // for aliased syms.
359     void * import;           // NOVELL & OS/2 only: imported symbol data.
360     offset cdefsize;         // altdef comdefs: size of comdef
361   } p;
362   union {
363     dos_sym_data d;
364     struct symbol * altdefs; // for keeping track of comdat & comdef defs
365     struct symbol * datasym; // altdef comdats: sym which has data def
366     int aliaslen;            // for aliases - length of name.
367   } u;
368   union {
369     struct symbol * mainsym; // altdefs: main symbol definition
370     struct symbol * def;     // for lazy externs
371     struct symbol **vfdata;  // for virtual function lazy externs.
372     void * export;           // OS/2 & PE only: exported sym info.
373   } e;
374   char * name;
375   char * prefix;             // primarily for netware, though could be
376                              // subverted for other use. gives symbol
377                              // namespace qualification
378 } symbol;
380 There are many SYM_ and ST_ constants describing various symbol properties.
382 Finally, calculation of segment addresses (during the second pass) is performed
383 in objcalc.c. Information produced during this process will be used later for
384 creating an executable file. One can iterate through the groups (i.e. grouped
385 segments) this way:
387 group_entry *currgrp;
389 for( currgrp = Groups; currgrp != NULL; currgrp = currgrp->next_group ) {
390   // Do something...
393 There are some important global variables. In the example above, we see Groups
394 is the list of all groups. Variable DataGroup specifies the data group,
395 variable NumGroups contains the total number of groups. Group entry is defined
398 $OWROOT/bld/wl/h/objstruc.h
400 typedef struct group_entry {
401   GROUP_ENTRY * next_group;
402   SEG_LEADER * leaders;
403   symbol * sym;
404   section * section;
405   targ_addr grp_addr;
406   unsigned_16 segflags;
407   offset size;
408   offset totalsize;
409   offset linear;         // preferred base address
410   union {
411     void * grp_relocs;   // OS2/ELF only.
412     class_entry * class; // CV (during addr calc )
413   } g;
414   union {
415     unsigned qnxflags;   // QNX
416     unsigned miscflags;  // OS/2
417   } u;
418   unsigned num;
419   unsigned isfree : 1;
420   unsigned isautogrp : 1;
421 } group_entry;
423 Here size is group size in the file; totalsize is group size in the memory
424 (e.g. uninitialized data do not require space in the file).
426 Another important global variable is FmtData. This structure contains fields
427 describing the format and various properties of the output file. For our
428 purposes, the most important fields are type and dll. For ELF shared objects,
429 the following test evaluates as TRUE: (FmtData.type & MK_ELF) && FmtData.dll.
431 [edit]
433 Load ELF
435 Definition
437 Part of Open Watcom Linker ($OWROOT/bld/wl), designed for writing executable
438 files in ELF format. Consists of two files: loadelf.c and loadelf2.c.
440 Description
442 Currently, LoadELF is able to create only ELF executable files (shared objects
443 are not supported). Most of the work is performed in loadelf.c. The second
444 file, loadelf2.c, contains only the routines for creating ELF symbol tables.
446 The main function is FiniELFLoadFile(). The following tasks are performed
447 there:
449  1. Initialize the ELF header, program headers, and section headers.
450  2. Write groups (i.e. code and data) to the ELF file (program and section
451     headers are changed during this process; i.e. sections: .text, .data, and
452     .bss).
453  3. Write relocation section (.rela.text).
454  4. Write DWARF debug information (if needed).
455  5. Write symbol table (.symtab), hash (.hash), and strings (.strtab).
456  6. Write section strings (.shstrtab).
457  7. Write section headers.
458  8. Write DWARF trailer (if needed).
459  9. Rewind and write the ELF header and program headers.
461 Task 1 is performed in void SetHeaders( ElfHdr *hdr ). Sections are initialized
462 in void InitSections( ElfHdr *hdr).
464 ElfHdr is defined as:
466 $OWROOT/bld/wl/h/loadelf2.h
468 typedef struct {
469   Elf32_Ehdr eh;
470   Elf32_Shdr *strhdr;
471   Elf32_Phdr *ph;
472   unsigned ph_size;
473   Elf32_Shdr *sh;
474   unsigned sh_size;
475   stringtable secstrtab;
476   struct {
477     int secstr;   // Index of strings section for section names
478     int grpbase;  // Index base for Groups in section
479     int grpnum;   // Number of groups
480     int relbase;  // Index base for relocation sections
481     int relnum;   // number of relocations
482     int symstr;   // Index of symbol's string table
483     int symtab;   // Index of symbol table
484     int symhash;  // Index of symbol hash table
485     int dbgbegin; // Index of first debug section
486     int dbgnum;   // Number of debug sections
487   } i;            // Indexes into sh
488   unsigned_32 curr_off;
489 } ElfHdr;
491 The most interesting structure is i, where section indexes are specified. This
492 structure is filled in InitSections(). So the order of sections is predefined.
494 Program header is created in SetHeaders() as well.
496 Task 2 is performed in void WriteELFGroups( ElfHdr *hdr ). In this function,
497 group list is iterated (as described in WLCore). For each group, code or data
498 are written to the ELF file, using WriteGroupLoad(). The corresponding program
499 headers and sections are filled as well, using SetGroupHeaders(). Note that
500 uninitialized data (.bss) are processed in the special way.
502 Relocations are written using void WriteRelocsSections( ElfHdr *hdr ). In this
503 implementation, all relocations are presented with explicit addends (i.e.
504 SHT_RELA).
506 Task 5 is performed by WriteElfSymTable( ElfSymTable *tab, ElfHdr *hdr, int
507 hashidx, int symtabidx, int strtabidx ). Both symbol table and hash are written
508 in this function. Then string table is written using WriteSHStrings().
510 Function WriteSHStrings() is reused for the next task (i.e. writing section
511 names).
513 Note that field curr_off (from ElfHdr) is widely used. This field specifies the
514 current offset in the ELF file. However, it is not updated automatically, e.g.
515 after WriteLoad() therefore precise calculations are needed to keep this value
516 up to date.
518 Functions to write ELF (and other) executable files are located in $OWROOT/bld/
519 wl/c/loadfile.c.
522 [edit]
524 GC386
526 Definition
528 Code Generator for 32-bit family of x86 CPUs, used by Open Watcom C Compiler
529 consists of three “layers”:
531   • General Code Generator, located in $OWROOT/bld/cg.
532   • Common x86 Code Generator (16/32-bit), located in $OWROOT/bld/cg/intel.
533   • Specific 32-bit x86 Code Generator, located in $OWROOT/bld/cg/intel/386.
535 Description
537 Documentation for the Code Generator ($OWROOT/bld/cg/doc) covers only the
538 interface to the code generator (i.e. "General Code Generator"). The code
539 generator (back end) interface is a set of procedure calls. These are divided
540 into Code Generation (CG), Data Generation (DG), miscellaneous Back End (BE),
541 Front end supplied (FE), and debugger information (DB) routines.
543 There is internal machine-independent format (allowing scalability, multiple
544 platforms, and machine-independent optimizations). The main parts of these
545 intermediate data (passed to the code generator for particular machine) are
546 "blocks" and "instructions":
548 $OWROOT/bld/cg/h/block.h
550 typedef struct block {
551   struct block_ins ins;
552   struct block *next_block; /* used for DFS */
553   struct block *prev_block;
554   union {
555     struct interval_def *interval;
556     struct block *partition;
557     struct block *loop;
558   } u;
559   struct block *loop_head;
560   struct data_flow_def *dataflow;
561   struct block_edge *input_edges;
562   pointer cc; /* AKA cc_control */
563   dominator_info dom; /* least node in dominator set */
564   type_length stack_depth; /* set by FlowSave stuff */
565   union {
566     struct block *alter_ego; /* used in loop unrolling */
567     struct block *next; /* used for CALL_LABEL kludge */
568   } v;
569   label_handle label; /* front end identification */
570   local_bit_set available_bit;
571   interval_depth depth; /* loop nesting depth */
572   block_num id; /* internal identification */
573   block_num gen_id;
574   block_num inputs; /* number of input edges */
575   block_num targets; /* number of target blocks */
576   block_class class;
577   signed_32 iterations;
578   unsigned_32 unroll_count;
579   struct block_edge edge[ 1 ];
580 } block;
582 $OWROOT/bld/cg/h/inslist.h
584 typedef struct ins_header {
585   struct instruction *prev;
586   struct instruction *next;
587   struct name_set live;
588   source_line_number line_num;
589   opcode_defs opcode;
590   instruction_state state;
591 } ins_header;
593 typedef struct instruction {
594   struct ins_header head;
595   struct opcode_entry *table;
597   union {
598     struct opcode_entry *gen_table;
599     struct instruction *parm_list;
600     struct instruction *cse_link;
601   } u;
603   struct register_name *zap;
604   union name *result; /* result location */
605   instruction_id id;
606   type_class_def type_class;
607   type_class_def base_type_class;
608   unsigned_16 sequence;
610 #include "cgnoalgn.h"
612   union {
613     byte byte;
614     bool bool;
615     call_flags call_flags;
616     nop_flags nop_flags;
617     byte zap_value; /* for conversions on AXP */
618   } flags;
620   union {
621     byte index_needs; /* a.k.a. reg_set_index */
622     byte stk_max;
623   } t;
625   byte stk_entry;
626   byte num_operands;
627   instruction_flags ins_flags;
628   byte stk_exit;
630   union {
631     byte stk_extra;
632     byte stk_depth;
633   } s;
635 #include "cgrealgn.h"
637   union name *operands[ 1 ]; /* operands */
639 } instruction;
641 Sample: Walking through the blocks and instructions
643 block *blk;
644 instruction *ins;
646 blk = HeadBlock;
647 while( blk != NULL ) {
648   ins = blk->ins.hd.next;
649   while( ins->head.opcode != OP_BLOCK ) {
650     // Do something...
651     ins = ins->head.next;
652   }
653   blk = blk->next_block;
656 Instructions are machine-independent. For example, opcode == OP_ADD specifies
657 addition. Operands and result have the name type that can represent CPU
658 register, memory location, immediate constant, etc.:
660 $OWROOT/bld/cg/h/name.h
662 typedef union name {
663   struct name_def n;
664   struct var_name v;
665   struct const_name c;
666   struct memory_name m;
667   struct temp_name t;
668   struct register_name r;
669   struct indexed_name i;
670   union name *_n;
671 } name;
673 This data looks like machine-dependent, since different architectures have
674 different registers. However, this is top-level abstraction. The code generator
675 for particular architecture supplies the corresponding set of registers.
676 Actually there are many register sets (e.g. stack pointer, registers for
677 temporary storage, fixed registers, etc.) The hw_reg_set type is able to hold
678 one or more registers (or be empty).
680 For 32-bit family of x86 processors, the register sets are defined in $OWROOT/
681 cg/intel/386/c/386rgtbl.c.
683 There are many inline functions operating with register sets ($OWROOT/cg/h/
684 cghwreg.h). Most of them implement "set arithmetic": HW_Asgn, HW_CAsgn,
685 HW_CEqual, HW_COnlyOn, HW_COvlap, HW_CSubset, HW_CTurnOff, HW_CTurnOn,
686 HW_Equal, HW_OnlyOn, HW_Ovlap, HW_Subset, HW_TurnOff, HW_TurnOn.
688 Sample: Excluding the EBX register (required for PIC)
690 hw_reg_set all;
692 // ...
693 HW_CTurnOff( all, HW_EBX );
695 There are two levels of code generation for x86: middle level and low level
696 (assuming high level is machine-independent).
698 High level uses instruction and related functions (only some are shown):
700 // Creating new instruction
702 instruction *MakeUnary( opcode_defs, name *, name *, type_class_def );
703 instruction *MakeBinary( opcode_defs, name *, name *, name *, type_class_def );
704 instruction *MakeMove( name *, name *, type_class_def );
706 // Miscellaneous allocations
708 name *AllocRegName( hw_reg_set );
709 name *AllocTemp( type_class_def );
710 name *AllocIntConst( int );
711 name *AllocUIntConst( uint );
713 // Placing the instruction
715 void AddIns( instruction * );
716 void PrefixIns( instruction *, instruction * );
717 void SuffixIns( instruction *, instruction * );
718 void ReplIns( instruction *, instruction * );
720 Sample: Generating add ebx, 0BABEh in the current block
722 name *ebx;
723 instruction *ins;
725 ebx = AllocRegName( HW_EBX );
726 ins = MakeBinary( OP_ADD, ebx, AllocIntConst( 0xBABE ), ebx, WD );
727 AddIns(ins);
729 At the low level, we generate the actual x86 opcodes (once and for all).
730 Transformation from middle level to low level is performed mainly by i86enc.c,
731 i86enc2.c ($OWROOT/bld/cg/intel), i86enc32.c ($OWROOT/bld/cg/intel/386).
733 There are several macros for emitting binary opcodes:
735 _Code;
736 . . .
737 _Next;
738 . . .
739 _Emit;
741 Opcodes are inserted using the special functions, e.g.:
743 void LayOpbyte( opcode op );
744 void LayOpword( opcode op );
745 void LayReg( hw_reg_set r );
746 void LayRegOp( name *r );
747 void LayRMRegOp( name *r );
749 Sample: Generating PUSHF
751 _Code;
752 LayOpbyte( 0x9C );
753 _Emit;
755 However, there are more digestible functions for common cases, e.g. GenRegMove
758 The information above should give the basic knowledge to the developer
759 unfamiliar with CG386. The last uncovered topic is how object files are
760 produced.
762 Unfortunately the only object format supported is OMF. Therefore many things in
763 CG386 are rigidly bound to OMF structure. OMF output is implemented mostly in
764 $OWROOT/bld/cg/intel/c/i86obj.c, i86esc.c, and $OWROOT/bld/cg/c/posixio.c.
766 But there is last but one stage, before data became written to the object file.
767 This stage is optimizing (although some optimizations were performed during
768 previous stages). The optimizer ($OWROOT/bld/cg/c/opt*.c) has the operations
769 queue. The “trace” below shows intercommunications between the optimizer and
770 OMF output routines (for well-known “Hello, world!” program):
772 #include <stdio.h>
774 int main(void) {
775   printf("Hello, world!\n");
776   return 0;
779 Trace:
781 i86obj.c: InitSegDefs()
782 i86obj.c: DefSegment(id=00000001(1),attr=00000007(7),str="_TEXT",align=00000001(1),use_16=FALSE)
783 i86obj.c: DefSegment(id=00000002(2),attr=0000001C(28),str="CONST",align=00000004(4),use_16=FALSE)
784 i86obj.c: DefSegment(id=00000003(3),attr=0000000C(12),str="CONST2",align=00000004(4),use_16=FALSE)
785 i86obj.c: DefSegment(id=00000004(4),attr=00000006(6),str="_DATA",align=00000004(4),use_16=FALSE)
786 i86obj.c: DefSegment(id=0000000B(11),attr=00000002(2),str="_BSS",align=00000004(4),use_16=FALSE)
787 i86obj.c: ObjInit()
788 i86obj.c: InitFPPatches()
789 i86obj.c: FillArray(res,size=00000001(1),starting=00000032(50),increment=00000032(50))
790 i86obj.c: OutName(name="hello.c",dst)
791 i86obj.c: NeedMore(arr,more=00000021(33))
792 i86obj.c: NeedMore(arr,more=00000002(2))
793 i86obj.c: OutString(name="OS220",dest)
794 i86obj.c: NeedMore(arr,more=00000005(5))
795 i86obj.c: NeedMore(arr,more=00000002(2))
796 i86obj.c: OutModel(dest)
797 i86obj.c: GetMemModel()
798 i86obj.c: OutString(name="3fOpd",dest)
799 i86obj.c: NeedMore(arr,more=00000005(5))
800 i86obj.c: NeedMore(arr,more=00000002(2))
801 i86obj.c: NeedMore(arr,more=00000001(1))
802 i86obj.c: NeedMore(arr,more=00000002(2))
803 i86obj.c: NeedMore(arr,more=00000004(4))
804 i86obj.c: OutName(name="hello.c",dst)
805 i86obj.c: NeedMore(arr,more=00000021(33))
806 i86obj.c: NeedMore(arr,more=00000002(2))
807 i86obj.c: NeedMore(arr,more=00000004(4))
808 i86obj.c: OutName(name="/usr/lib/dietlibc/include/stdio.h",dst)
809 i86obj.c: NeedMore(arr,more=00000022(34))
810 i86obj.c: NeedMore(arr,more=00000002(2))
811 i86obj.c: NeedMore(arr,more=00000004(4))
812 i86obj.c: OutName(name="/usr/lib/dietlibc/include/sys/cdefs.h",dst)
813 i86obj.c: NeedMore(arr,more=00000026(38))
814 i86obj.c: NeedMore(arr,more=00000002(2))
815 i86obj.c: NeedMore(arr,more=00000004(4))
816 i86obj.c: OutName(name="/usr/lib/dietlibc/include/sys/types.h",dst)
817 i86obj.c: NeedMore(arr,more=00000026(38))
818 i86obj.c: NeedMore(arr,more=00000002(2))
819 i86obj.c: NeedMore(arr,more=00000004(4))
820 i86obj.c: OutName(name="/usr/lib/dietlibc/include/inttypes.h",dst)
821 i86obj.c: NeedMore(arr,more=00000025(37))
822 i86obj.c: NeedMore(arr,more=00000002(2))
823 i86obj.c: NeedMore(arr,more=00000004(4))
824 i86obj.c: OutName(name="/usr/lib/dietlibc/include/endian.h",dst)
825 i86obj.c: NeedMore(arr,more=00000023(35))
826 i86obj.c: NeedMore(arr,more=00000002(2))
827 i86obj.c: NeedMore(arr,more=00000004(4))
828 i86obj.c: OutName(name="/usr/lib/dietlibc/include/stddef.h",dst)
829 i86obj.c: NeedMore(arr,more=00000023(35))
830 i86obj.c: NeedMore(arr,more=00000002(2))
831 i86obj.c: NeedMore(arr,more=00000004(4))
832 i86obj.c: OutName(name="/usr/lib/dietlibc/include/sys/stat.h",dst)
833 i86obj.c: NeedMore(arr,more=00000025(37))
834 i86obj.c: NeedMore(arr,more=00000002(2))
835 i86obj.c: NeedMore(arr,more=00000004(4))
836 i86obj.c: OutName(name="/usr/lib/dietlibc/include/stdarg.h",dst)
837 i86obj.c: NeedMore(arr,more=00000023(35))
838 i86obj.c: NeedMore(arr,more=00000002(2))
839 i86obj.c: NeedMore(arr,more=00000004(4))
840 i86obj.c: OutName(name="/usr/lib/dietlibc/include/stdarg-cruft.h",dst)
841 i86obj.c: NeedMore(arr,more=00000029(41))
842 i86obj.c: NeedMore(arr,more=00000002(2))
843 i86obj.c: FillArray(res,size=00000001(1),starting=00000005(5),increment=00000005(5))
844 i86obj.c: FillArray(res,size=00000001(1),starting=00000005(5),increment=00000005(5))
845 i86obj.c: DoSegGrpNames(dgroup_def,tgroup_def)
846 i86obj.c: GetNameIdx(name="",suff,alloc=)
847 i86obj.c: GetNameIdx(name="CODE",suff,alloc=)
848 i86obj.c: GetNameIdx(name="DATA",suff,alloc=)
849 i86obj.c: GetNameIdx(name="BSS",suff,alloc=)
850 i86obj.c: GetNameIdx(name="TLS",suff,alloc=)
851 i86obj.c: GetNameIdx(name="FLAT",suff,alloc=)
852 i86obj.c: GetNameIdx(name="DGROUP",suff,alloc=)
853 i86obj.c: OutIdx(value=00000007(7),dest)
854 i86obj.c: NeedMore(arr,more=00000002(2))
855 i86obj.c: FillArray(res,size=00000040(64),starting=00000005(5),increment=00000005(5))
856 i86obj.c: DoSegment(seg,dgroup_def,tgroup_def,use_16=FALSE)
857 i86obj.c: AskSegIndex(seg=00000001(1))
858 i86obj.c: NeedMore(arr,more=00000001(1))
859 i86obj.c: SegmentAttr(align=00000001(1),tipe=00000007(7),use_16=FALSE)
860 i86obj.c: GetNameIdx(name="_TEXT",suff,alloc=)
861 i86obj.c: SegmentClass(rec)
862 i86obj.c: DoASegDef(rec,use_16=FALSE)
863 i86obj.c: FillArray(res,size=00000001(1),starting=00000100(256),increment=00000100(256))
864 i86obj.c: FillArray(res,size=00000001(1),starting=00000014(20),increment=00000032(50))
865 i86obj.c: FillArray(res,size=00000001(1),starting=00000100(256),increment=00000032(50))
866 i86obj.c: OutByte(value=00000029(41))
867 i86obj.c: NeedMore(arr,more=00000001(1))
868 i86obj.c: OutOffset(value=00000000(0))
869 i86obj.c: NeedMore(arr,more=00000004(4))
870 i86obj.c: OutIdx(value=00000008(8),dest)
871 i86obj.c: NeedMore(arr,more=00000002(2))
872 i86obj.c: OutIdx(value=00000002(2),dest)
873 i86obj.c: NeedMore(arr,more=00000002(2))
874 i86obj.c: OutIdx(value=00000001(1),dest)
875 i86obj.c: NeedMore(arr,more=00000002(2))
876 i86obj.c: FlushNames()
877 i86obj.c: PickOMF(cmd=00000098(152))
878 i86obj.c: OutInt(value=0000FE80(65152))
879 i86obj.c: NeedMore(arr,more=00000002(2))
880 i86obj.c: OutByte(value=0000004F(79))
881 i86obj.c: NeedMore(arr,more=00000001(1))
882 i86obj.c: OutIdx(value=00000001(1),dest)
883 i86obj.c: NeedMore(arr,more=00000002(2))
884 i86obj.c: DoSegment(seg,dgroup_def,tgroup_def,use_16=FALSE)
885 i86obj.c: AskSegIndex(seg=00000002(2))
886 i86obj.c: NeedMore(arr,more=00000001(1))
887 i86obj.c: SegmentAttr(align=00000004(4),tipe=0000001C(28),use_16=FALSE)
888 i86obj.c: OutGroup(sidx=00000002(2),group_def,index_p)
889 i86obj.c: NeedMore(arr,more=00000001(1))
890 i86obj.c: OutIdx(value=00000002(2),dest)
891 i86obj.c: NeedMore(arr,more=00000002(2))
892 i86obj.c: GetNameIdx(name="",suff,alloc=CONST)
893 i86obj.c: SegmentClass(rec)
894 i86obj.c: DoASegDef(rec,use_16=FALSE)
895 i86obj.c: FillArray(res,size=00000001(1),starting=00000100(256),increment=00000100(256))
896 i86obj.c: FillArray(res,size=00000001(1),starting=00000014(20),increment=00000032(50))
897 i86obj.c: OutByte(value=000000A9(169))
898 i86obj.c: NeedMore(arr,more=00000001(1))
899 i86obj.c: OutOffset(value=00000000(0))
900 i86obj.c: NeedMore(arr,more=00000004(4))
901 i86obj.c: OutIdx(value=00000009(9),dest)
902 i86obj.c: NeedMore(arr,more=00000002(2))
903 i86obj.c: OutIdx(value=00000003(3),dest)
904 i86obj.c: NeedMore(arr,more=00000002(2))
905 i86obj.c: OutIdx(value=00000001(1),dest)
906 i86obj.c: NeedMore(arr,more=00000002(2))
907 i86obj.c: FlushNames()
908 i86obj.c: PickOMF(cmd=00000098(152))
909 i86obj.c: DoSegment(seg,dgroup_def,tgroup_def,use_16=FALSE)
910 i86obj.c: AskSegIndex(seg=00000003(3))
911 i86obj.c: NeedMore(arr,more=00000001(1))
912 i86obj.c: SegmentAttr(align=00000004(4),tipe=0000000C(12),use_16=FALSE)
913 i86obj.c: OutGroup(sidx=00000003(3),group_def,index_p)
914 i86obj.c: NeedMore(arr,more=00000001(1))
915 i86obj.c: OutIdx(value=00000003(3),dest)
916 i86obj.c: NeedMore(arr,more=00000002(2))
917 i86obj.c: GetNameIdx(name="",suff,alloc=CONST2)
918 i86obj.c: SegmentClass(rec)
919 i86obj.c: DoASegDef(rec,use_16=FALSE)
920 i86obj.c: FillArray(res,size=00000001(1),starting=00000100(256),increment=00000100(256))
921 i86obj.c: FillArray(res,size=00000001(1),starting=00000014(20),increment=00000032(50))
922 i86obj.c: OutByte(value=000000A9(169))
923 i86obj.c: NeedMore(arr,more=00000001(1))
924 i86obj.c: OutOffset(value=00000000(0))
925 i86obj.c: NeedMore(arr,more=00000004(4))
926 i86obj.c: OutIdx(value=0000000A(10),dest)
927 i86obj.c: NeedMore(arr,more=00000002(2))
928 i86obj.c: OutIdx(value=00000003(3),dest)
929 i86obj.c: NeedMore(arr,more=00000002(2))
930 i86obj.c: OutIdx(value=00000001(1),dest)
931 i86obj.c: NeedMore(arr,more=00000002(2))
932 i86obj.c: FlushNames()
933 i86obj.c: PickOMF(cmd=00000098(152))
934 i86obj.c: DoSegment(seg,dgroup_def,tgroup_def,use_16=FALSE)
935 i86obj.c: AskSegIndex(seg=00000004(4))
936 i86obj.c: NeedMore(arr,more=00000001(1))
937 i86obj.c: SegmentAttr(align=00000004(4),tipe=00000006(6),use_16=FALSE)
938 i86obj.c: OutGroup(sidx=00000004(4),group_def,index_p)
939 i86obj.c: NeedMore(arr,more=00000001(1))
940 i86obj.c: OutIdx(value=00000004(4),dest)
941 i86obj.c: NeedMore(arr,more=00000002(2))
942 i86obj.c: GetNameIdx(name="",suff,alloc=_DATA)
943 i86obj.c: SegmentClass(rec)
944 i86obj.c: DoASegDef(rec,use_16=FALSE)
945 i86obj.c: FillArray(res,size=00000001(1),starting=00000100(256),increment=00000100(256))
946 i86obj.c: FillArray(res,size=00000001(1),starting=00000014(20),increment=00000032(50))
947 i86obj.c: OutByte(value=000000A9(169))
948 i86obj.c: NeedMore(arr,more=00000001(1))
949 i86obj.c: OutOffset(value=00000000(0))
950 i86obj.c: NeedMore(arr,more=00000004(4))
951 i86obj.c: OutIdx(value=0000000B(11),dest)
952 i86obj.c: NeedMore(arr,more=00000002(2))
953 i86obj.c: OutIdx(value=00000003(3),dest)
954 i86obj.c: NeedMore(arr,more=00000002(2))
955 i86obj.c: OutIdx(value=00000001(1),dest)
956 i86obj.c: NeedMore(arr,more=00000002(2))
957 i86obj.c: FlushNames()
958 i86obj.c: PickOMF(cmd=00000098(152))
959 i86obj.c: DoSegment(seg,dgroup_def,tgroup_def,use_16=FALSE)
960 i86obj.c: AskSegIndex(seg=0000000B(11))
961 i86obj.c: NeedMore(arr,more=00000001(1))
962 i86obj.c: SegmentAttr(align=00000004(4),tipe=00000002(2),use_16=FALSE)
963 i86obj.c: OutGroup(sidx=00000005(5),group_def,index_p)
964 i86obj.c: NeedMore(arr,more=00000001(1))
965 i86obj.c: OutIdx(value=00000005(5),dest)
966 i86obj.c: NeedMore(arr,more=00000002(2))
967 i86obj.c: GetNameIdx(name="",suff,alloc=_BSS)
968 i86obj.c: SegmentClass(rec)
969 i86obj.c: DoASegDef(rec,use_16=FALSE)
970 i86obj.c: FillArray(res,size=00000001(1),starting=00000100(256),increment=00000100(256))
971 i86obj.c: FillArray(res,size=00000001(1),starting=00000014(20),increment=00000032(50))
972 i86obj.c: OutByte(value=000000A9(169))
973 i86obj.c: NeedMore(arr,more=00000001(1))
974 i86obj.c: OutOffset(value=00000000(0))
975 i86obj.c: NeedMore(arr,more=00000004(4))
976 i86obj.c: OutIdx(value=0000000C(12),dest)
977 i86obj.c: NeedMore(arr,more=00000002(2))
978 i86obj.c: OutIdx(value=00000004(4),dest)
979 i86obj.c: NeedMore(arr,more=00000002(2))
980 i86obj.c: OutIdx(value=00000001(1),dest)
981 i86obj.c: NeedMore(arr,more=00000002(2))
982 i86obj.c: FlushNames()
983 i86obj.c: PickOMF(cmd=00000098(152))
984 i86obj.c: FlushNames()
985 i86obj.c: KillArray(arr)
986 i86obj.c: KillStatic(arr)
987 i86obj.c: OutIdx(value=00000006(6),dest)
988 i86obj.c: NeedMore(arr,more=00000002(2))
989 i86obj.c: FlushNames()
990 i86obj.c: KillArray(arr)
991 i86obj.c: KillStatic(arr)
992 i86obj.c: AskSegIndex(seg=00000001(1))
993 i86obj.c: KillArray(arr)
994 i86obj.c: KillStatic(arr)
995 i86obj.c: TellObjNewProc(proc=00000085(133))
996 i86obj.c: SetOP(seg=00000001(1))
997 i86obj.c: AskSegIndex(seg=00000001(1))
998 i86obj.c: SetOP(seg=00000001(1))
999 i86obj.c: AskSegIndex(seg=00000001(1))
1000 i86obj.c: AskNameCode(hdl=00000049(73),class=00000000(0))
1001 i86obj.c: AskBackSeg()
1002 i86obj.c: SetOP(seg=00000002(2))
1003 i86obj.c: AskSegIndex(seg=00000002(2))
1004 i86obj.c: TellObjNewLabel(lbl=00000000(0))
1005 i86obj.c: SetUpObj(is_data=TRUE)
1006 i86obj.c: CheckLEDataSize(max_size=00000010(16),need_init=FALSE)
1007 i86obj.c: OutLabel(lbl=0811B9C8(135379400))
1008 i86obj.c: InitPatch()
1009 i86obj.c: FillArray(res,size=0000000C(12),starting=0000000A(10),increment=0000000A(10))
1010 i86obj.c: KillArray(arr)
1011 i86obj.c: KillStatic(arr)
1012 i86obj.c: AskOP()
1013 i86obj.c: SetUpObj(is_data=TRUE)
1014 i86obj.c: CheckLEDataSize(max_size=00000010(16),need_init=FALSE)
1015 i86obj.c: OutDBytes(len=0000000F(15),src)
1016 i86obj.c: SetPendingLine()
1017 i86obj.c: CheckLEDataSize(max_size=00000001(1),need_init=TRUE)
1018 i86obj.c: OutLEDataStart(iterated=FALSE)
1019 i86obj.c: OutIdx(value=00000002(2),dest)
1020 i86obj.c: NeedMore(arr,more=00000002(2))
1021 i86obj.c: OutOffset(value=00000000(0))
1022 i86obj.c: NeedMore(arr,more=00000004(4))
1023 i86obj.c: NeedMore(arr,more=0000000F(15))
1024 i86obj.c: IncLocation(by=0000000F(15))
1025 i86obj.c: SetBigLocation(loc=0000000F(15))
1026 i86obj.c: SetMaxWritten()
1027 i86obj.c: SetOP(seg=00000001(1))
1028 i86obj.c: AskSegIndex(seg=00000001(1))
1029 i86obj.c: AskNameCode(hdl=0811BE38(135380536),class=00000002(2))
1030 i86obj.c: AskSegID(hdl=0811BE38(135380536),class=00000002(2))
1031 i86obj.c: AskSegPrivate(id=00000002(2))
1032 i86obj.c: AskSegIndex(seg=00000002(2))
1033 i86obj.c: AskSegID(hdl=0811BE38(135380536),class=00000002(2))
1034 i86obj.c: AskSegNear(id=00000002(2))
1035 i86obj.c: AskSegIndex(seg=00000002(2))
1036 i86obj.c: AskBackSeg()
1037 i86obj.c: AskCodeSeg()
1038 i86obj.c: SetOP(seg=00000001(1))
1039 i86obj.c: AskSegIndex(seg=00000001(1))
1040 optmain.c: InputOC(oc)
1041 optmain.c: LDone(oc)
1042 i86obj.c: SetOP(seg=00000001(1))
1043 i86obj.c: AskSegIndex(seg=00000001(1))
1044 i86obj.c: AskCodeSeg()
1045 i86obj.c: SetOP(seg=00000001(1))
1046 i86obj.c: AskSegIndex(seg=00000001(1))
1047 optmain.c: InputOC(oc)
1048 optmain.c: LDone(oc)
1049 i86esc.c: DoSymRef(opnd,val=00000000(0),base=FALSE)
1050 i86esc.c: DoFESymRef(sym=0811BE38(135380536),class=00000002(2),val=00000000(0),fixup=00000001(1))
1051 i86obj.c: AskSegID(hdl=0811BE38(135380536),class=00000002(2))
1052 i86esc.c: DoRelocRef(sym=0811BE38(135380536),class=00000002(2),seg=00000002(2),val=00000000(0),kind=00000000(0))
1053 optmain.c: InputOC(oc)
1054 optmain.c: LDone(oc)
1055 optmain.c: InputOC(oc)
1056 optmain.c: LDone(oc)
1057 optmain.c: InputOC(oc)
1058 optmain.c: LDone(oc)
1059 optmain.c: InputOC(oc)
1060 optmain.c: LDone(oc)
1061 optmain.c: InputOC(oc)
1062 optmain.c: LDone(oc)
1063 i86obj.c: SetOP(seg=00000001(1))
1064 i86obj.c: AskSegIndex(seg=00000001(1))
1065 i86obj.c: AskCodeSeg()
1066 i86obj.c: SetOP(seg=00000001(1))
1067 i86obj.c: AskSegIndex(seg=00000001(1))
1068 i86esc.c: CodeHasAbsPatch(code)
1069 i86esc.c: CodeHasAbsPatch(code)
1070 i86esc.c: CodeHasAbsPatch(code)
1071 i86esc.c: OutputOC(oc,next_lbl)
1072 i86obj.c: SetUpObj(is_data=FALSE)
1073 i86obj.c: CheckLEDataSize(max_size=00000010(16),need_init=FALSE)
1074 i86obj.c: AskLocation()
1075 i86esc.c: DoAlignment(len=00000000(0))
1076 i86obj.c: SavePendingLine(new=00000000(0))
1077 i86esc.c: SendBytes(ptr,len=00000000(0))
1078 i86obj.c: SavePendingLine(new=00000000(0))
1079 i86obj.c: OutLabel(lbl=0811BE00(135380480))
1080 i86obj.c: UseImportForm(attr=00000007(7))
1081 i86obj.c: OutExport(sym=00000085(133))
1082 i86obj.c: OutIdx(value=00000002(2),dest)
1083 i86obj.c: NeedMore(arr,more=00000002(2))
1084 i86obj.c: OutIdx(value=00000001(1),dest)
1085 i86obj.c: NeedMore(arr,more=00000002(2))
1086 i86obj.c: OutObjectName(sym=00000085(133),dest)
1087 i86obj.c: OutName(name="main",dst)
1088 i86obj.c: NeedMore(arr,more=00000005(5))
1089 i86obj.c: NeedMore(arr,more=00000004(4))
1090 i86obj.c: OutIdx(value=00000000(0),dest)
1091 i86obj.c: NeedMore(arr,more=00000002(2))
1092 i86obj.c: InitPatch()
1093 i86obj.c: FillArray(res,size=0000000C(12),starting=0000000A(10),increment=0000000A(10))
1094 i86obj.c: KillArray(arr)
1095 i86obj.c: KillStatic(arr)
1096 i86esc.c: DumpSavedDebug()
1097 i86esc.c: OutputOC(oc,next_lbl)
1098 i86obj.c: SetUpObj(is_data=FALSE)
1099 i86obj.c: CheckLEDataSize(max_size=00000010(16),need_init=FALSE)
1100 i86obj.c: AskLocation()
1101 i86esc.c: DoAlignment(len=00000000(0))
1102 i86obj.c: SavePendingLine(new=00000000(0))
1103 i86esc.c: SendBytes(ptr,len=00000000(0))
1104 i86obj.c: SavePendingLine(new=00000000(0))
1105 i86obj.c: OutLabel(lbl=0811BC0C(135379980))
1106 i86obj.c: InitPatch()
1107 i86obj.c: FillArray(res,size=0000000C(12),starting=0000000A(10),increment=0000000A(10))
1108 i86obj.c: KillArray(arr)
1109 i86obj.c: KillStatic(arr)
1110 i86esc.c: DumpSavedDebug()
1111 i86esc.c: OutputOC(oc,next_lbl)
1112 i86esc.c: DumpSavedDebug()
1113 i86obj.c: SetUpObj(is_data=FALSE)
1114 i86obj.c: CheckLEDataSize(max_size=00000010(16),need_init=FALSE)
1115 i86esc.c: ExpandObj(cur,explen=00000009(9))
1116 i86obj.c: OutDBytes(len=00000001(1),src)
1117 i86obj.c: SetPendingLine()
1118 i86obj.c: CheckLEDataSize(max_size=00000001(1),need_init=TRUE)
1119 i86obj.c: OutLEDataStart(iterated=FALSE)
1120 i86obj.c: OutIdx(value=00000001(1),dest)
1121 i86obj.c: NeedMore(arr,more=00000002(2))
1122 i86obj.c: OutOffset(value=00000000(0))
1123 i86obj.c: NeedMore(arr,more=00000004(4))
1124 i86obj.c: NeedMore(arr,more=00000001(1))
1125 i86obj.c: IncLocation(by=00000001(1))
1126 i86obj.c: SetBigLocation(loc=00000001(1))
1127 i86obj.c: SetMaxWritten()
1128 i86obj.c: OutReloc(seg=00000002(2),class=00000001(1),rel=FALSE)
1129 i86obj.c: AskSegIndex(seg=00000002(2))
1130 i86obj.c: CheckLEDataSize(max_size=0000000C(12),need_init=TRUE)
1131 i86obj.c: OutLEDataStart(iterated=FALSE)
1132 i86obj.c: DoFix(idx=00000001(1),rel=FALSE,base=00000001(1),class=00000001(1),sidx=00000002(2))
1133 i86obj.c: NeedMore(arr,more=00000003(3))
1134 i86obj.c: AskIndexRec(sidx=00000002(2))
1135 i86obj.c: OutIdx(value=00000002(2),dest)
1136 i86obj.c: NeedMore(arr,more=00000002(2))
1137 i86obj.c: OutIdx(value=00000002(2),dest)
1138 i86obj.c: NeedMore(arr,more=00000002(2))
1139 i86obj.c: OutDataLong(value=00000000(0))
1140 i86obj.c: OutDataInt(value=00000000(0))
1141 i86obj.c: SetPendingLine()
1142 i86obj.c: CheckLEDataSize(max_size=00000002(2),need_init=TRUE)
1143 i86obj.c: OutLEDataStart(iterated=FALSE)
1144 i86obj.c: IncLocation(by=00000002(2))
1145 i86obj.c: SetBigLocation(loc=00000003(3))
1146 i86obj.c: NeedMore(arr,more=00000002(2))
1147 i86obj.c: SetMaxWritten()
1148 i86obj.c: OutDataInt(value=00000000(0))
1149 i86obj.c: SetPendingLine()
1150 i86obj.c: CheckLEDataSize(max_size=00000002(2),need_init=TRUE)
1151 i86obj.c: OutLEDataStart(iterated=FALSE)
1152 i86obj.c: IncLocation(by=00000002(2))
1153 i86obj.c: SetBigLocation(loc=00000005(5))
1154 i86obj.c: NeedMore(arr,more=00000002(2))
1155 i86obj.c: SetMaxWritten()
1156 i86esc.c: OutputOC(oc,next_lbl)
1157 i86esc.c: DumpSavedDebug()
1158 i86obj.c: SetUpObj(is_data=FALSE)
1159 i86obj.c: CheckLEDataSize(max_size=00000010(16),need_init=FALSE)
1160 i86esc.c: ExpandCJ(oc)
1161 i86obj.c: OutDataByte(value=000000E8(232))
1162 i86obj.c: SetPendingLine()
1163 i86obj.c: CheckLEDataSize(max_size=00000001(1),need_init=TRUE)
1164 i86obj.c: OutLEDataStart(iterated=FALSE)
1165 i86obj.c: IncLocation(by=00000001(1))
1166 i86obj.c: SetBigLocation(loc=00000006(6))
1167 i86obj.c: NeedMore(arr,more=00000001(1))
1168 i86obj.c: SetMaxWritten()
1169 i86esc.c: OutCodeDisp(lbl=0811AF38(135376696),f=00000001(1),rel=TRUE,class=00000008(8))
1170 i86obj.c: UseImportForm(attr=0000000F(15))
1171 i86obj.c: OutImport(sym=00000049(73),class=00000001(1),rel=TRUE)
1172 i86obj.c: FillArray(res,size=00000001(1),starting=00000100(256),increment=00000032(50))
1173 i86obj.c: CheckImportSwitch(next_is_static=FALSE)
1174 i86obj.c: OutName(name="printf",dst)
1175 i86obj.c: NeedMore(arr,more=00000007(7))
1176 i86obj.c: OutIdx(value=00000000(0),dest)
1177 i86obj.c: NeedMore(arr,more=00000002(2))
1178 i86obj.c: DumpImportResolve(sym=00000049(73),idx=00000001(1))
1179 i86obj.c: OutSpecialCommon(imp_idx=00000001(1),class=00000001(1),rel=TRUE)
1180 i86obj.c: CheckLEDataSize(max_size=0000000C(12),need_init=TRUE)
1181 i86obj.c: OutLEDataStart(iterated=FALSE)
1182 i86obj.c: DoFix(idx=00000001(1),rel=TRUE,base=00000002(2),class=00000001(1),sidx=00000000(0))
1183 i86obj.c: NeedMore(arr,more=00000003(3))
1184 i86obj.c: OutIdx(value=00000002(2),dest)
1185 i86obj.c: NeedMore(arr,more=00000002(2))
1186 i86obj.c: OutIdx(value=00000001(1),dest)
1187 i86obj.c: NeedMore(arr,more=00000002(2))
1188 i86obj.c: OutDataLong(value=00000000(0))
1189 i86obj.c: OutDataInt(value=00000000(0))
1190 i86obj.c: SetPendingLine()
1191 i86obj.c: CheckLEDataSize(max_size=00000002(2),need_init=TRUE)
1192 i86obj.c: OutLEDataStart(iterated=FALSE)
1193 i86obj.c: IncLocation(by=00000002(2))
1194 i86obj.c: SetBigLocation(loc=00000008(8))
1195 i86obj.c: NeedMore(arr,more=00000002(2))
1196 i86obj.c: SetMaxWritten()
1197 i86obj.c: OutDataInt(value=00000000(0))
1198 i86obj.c: SetPendingLine()
1199 i86obj.c: CheckLEDataSize(max_size=00000002(2),need_init=TRUE)
1200 i86obj.c: OutLEDataStart(iterated=FALSE)
1201 i86obj.c: IncLocation(by=00000002(2))
1202 i86obj.c: SetBigLocation(loc=0000000A(10))
1203 i86obj.c: NeedMore(arr,more=00000002(2))
1204 i86obj.c: SetMaxWritten()
1205 i86esc.c: OutputOC(oc,next_lbl)
1206 i86esc.c: DumpSavedDebug()
1207 i86obj.c: SetUpObj(is_data=FALSE)
1208 i86obj.c: CheckLEDataSize(max_size=00000010(16),need_init=FALSE)
1209 i86esc.c: ExpandObj(cur,explen=00000003(3))
1210 i86obj.c: OutDBytes(len=00000003(3),src)
1211 i86obj.c: SetPendingLine()
1212 i86obj.c: CheckLEDataSize(max_size=00000001(1),need_init=TRUE)
1213 i86obj.c: OutLEDataStart(iterated=FALSE)
1214 i86obj.c: NeedMore(arr,more=00000003(3))
1215 i86obj.c: IncLocation(by=00000003(3))
1216 i86obj.c: SetBigLocation(loc=0000000D(13))
1217 i86obj.c: SetMaxWritten()
1218 i86esc.c: OutputOC(oc,next_lbl)
1219 i86esc.c: DumpSavedDebug()
1220 i86obj.c: SetUpObj(is_data=FALSE)
1221 i86obj.c: CheckLEDataSize(max_size=00000010(16),need_init=FALSE)
1222 i86esc.c: ExpandObj(cur,explen=00000002(2))
1223 i86obj.c: OutDBytes(len=00000002(2),src)
1224 i86obj.c: SetPendingLine()
1225 i86obj.c: CheckLEDataSize(max_size=00000001(1),need_init=TRUE)
1226 i86obj.c: OutLEDataStart(iterated=FALSE)
1227 i86obj.c: NeedMore(arr,more=00000002(2))
1228 i86obj.c: IncLocation(by=00000002(2))
1229 i86obj.c: SetBigLocation(loc=0000000F(15))
1230 i86obj.c: SetMaxWritten()
1231 i86esc.c: OutputOC(oc,next_lbl)
1232 i86esc.c: DumpSavedDebug()
1233 i86obj.c: SetUpObj(is_data=FALSE)
1234 i86obj.c: CheckLEDataSize(max_size=00000010(16),need_init=FALSE)
1235 i86obj.c: OutDataByte(value=000000C3(195))
1236 i86obj.c: SetPendingLine()
1237 i86obj.c: CheckLEDataSize(max_size=00000001(1),need_init=TRUE)
1238 i86obj.c: OutLEDataStart(iterated=FALSE)
1239 i86obj.c: IncLocation(by=00000001(1))
1240 i86obj.c: SetBigLocation(loc=00000010(16))
1241 i86obj.c: NeedMore(arr,more=00000001(1))
1242 i86obj.c: SetMaxWritten()
1243 i86obj.c: SetOP(seg=00000001(1))
1244 i86obj.c: AskSegIndex(seg=00000001(1))
1245 i86obj.c: AskCodeSeg()
1246 i86obj.c: SetOP(seg=00000001(1))
1247 i86obj.c: AskSegIndex(seg=00000001(1))
1248 i86obj.c: ObjFini()
1249 i86obj.c: FiniTarg()
1250 i86obj.c: FlushObject()
1251 i86obj.c: SetUpObj(is_data=FALSE)
1252 i86obj.c: CheckLEDataSize(max_size=00000010(16),need_init=FALSE)
1253 i86obj.c: GenComdef()
1254 i86obj.c: EjectLEData()
1255 i86obj.c: EjectImports()
1256 i86obj.c: SetPatches()
1257 i86obj.c: SetAbsPatches()
1258 i86obj.c: PickOMF(cmd=000000A0(160))
1259 i86obj.c: PickOMF(cmd=0000009C(156))
1260 i86obj.c: EjectExports()
1261 i86obj.c: PickOMF(cmd=00000090(144))
1262 i86obj.c: FreeObjCache()
1263 i86obj.c: FlushNames()
1264 i86obj.c: KillArray(arr)
1265 i86obj.c: KillStatic(arr)
1266 i86obj.c: AskIndexRec(sidx=00000001(1))
1267 i86obj.c: KillStatic(arr)
1268 i86obj.c: KillStatic(arr)
1269 i86obj.c: FiniTarg()
1270 i86obj.c: FlushObject()
1271 i86obj.c: SetUpObj(is_data=FALSE)
1272 i86obj.c: CheckLEDataSize(max_size=00000010(16),need_init=FALSE)
1273 i86obj.c: GenComdef()
1274 i86obj.c: EjectLEData()
1275 i86obj.c: EjectImports()
1276 i86obj.c: SetPatches()
1277 i86obj.c: SetAbsPatches()
1278 i86obj.c: PickOMF(cmd=000000A0(160))
1279 i86obj.c: EjectExports()
1280 i86obj.c: FreeObjCache()
1281 i86obj.c: AskIndexRec(sidx=00000002(2))
1282 i86obj.c: KillStatic(arr)
1283 i86obj.c: KillStatic(arr)
1284 i86obj.c: FiniTarg()
1285 i86obj.c: FlushObject()
1286 i86obj.c: SetUpObj(is_data=FALSE)
1287 i86obj.c: CheckLEDataSize(max_size=00000010(16),need_init=FALSE)
1288 i86obj.c: GenComdef()
1289 i86obj.c: EjectLEData()
1290 i86obj.c: EjectImports()
1291 i86obj.c: EjectExports()
1292 i86obj.c: FreeObjCache()
1293 i86obj.c: AskIndexRec(sidx=00000003(3))
1294 i86obj.c: KillStatic(arr)
1295 i86obj.c: KillStatic(arr)
1296 i86obj.c: FiniTarg()
1297 i86obj.c: FlushObject()
1298 i86obj.c: SetUpObj(is_data=FALSE)
1299 i86obj.c: CheckLEDataSize(max_size=00000010(16),need_init=FALSE)
1300 i86obj.c: GenComdef()
1301 i86obj.c: EjectLEData()
1302 i86obj.c: EjectImports()
1303 i86obj.c: EjectExports()
1304 i86obj.c: FreeObjCache()
1305 i86obj.c: AskIndexRec(sidx=00000004(4))
1306 i86obj.c: KillStatic(arr)
1307 i86obj.c: KillStatic(arr)
1308 i86obj.c: FiniTarg()
1309 i86obj.c: FlushObject()
1310 i86obj.c: SetUpObj(is_data=FALSE)
1311 i86obj.c: CheckLEDataSize(max_size=00000010(16),need_init=FALSE)
1312 i86obj.c: GenComdef()
1313 i86obj.c: EjectLEData()
1314 i86obj.c: EjectImports()
1315 i86obj.c: EjectExports()
1316 i86obj.c: FreeObjCache()
1317 i86obj.c: AskIndexRec(sidx=00000005(5))
1318 i86obj.c: KillStatic(arr)
1319 i86obj.c: KillStatic(arr)
1320 i86obj.c: KillArray(arr)
1321 i86obj.c: KillStatic(arr)
1322 i86obj.c: KillArray(arr)
1323 i86obj.c: KillStatic(arr)
1324 i86obj.c: FiniAbsPatches()
1325 i86obj.c: EndModule()
1327 This trace shows how OMF object file is written in i86obj.c. We will refer to
1328 this trace in the latter sections.
1330 OMF file is composed of object records. These records contain miscellaneous
1331 linking information, e.g.:
1333   • EXTDEF External Names Definition Record (imported symbols)
1334   • PUBDEF Public Names Definition Record (exported symbols)
1335   • SEGDEF Segment Definition Record (describes a logical segment)
1336   • GRPDEF Group Definition Record (segments to be collected together)
1337   • FIXUPP Fixup Record (relocations)
1338   • BAKPAT Backpatch Record (relocations)
1339   • LEDATA Logical Enumerated Data Record (binary code or data)
1341 Actual writing is performed by void PutObjRec( byte class, byte *buff, uint len
1342 ) located in posixio.c. For example, class of LEDATA is either 0xA0 or 0xA1.
1345 [edit]
1349 Definition
1351 Abbreviation of “Object Writing Library”. Located in $OWROOT/bld/owl.
1353 OWL is designed for writing object files in ELF and COFF formats. We are
1354 interested mainly in the ELF (owelf.c). However, OWL is not an abstract wrapper
1355 (like ORL). But rather a set of data structures and functions, useful for
1356 creating object files.
1358 Description
1360 OWL is currently used by RISC code generators (Alpha AXP and PowerPC). As
1361 mentioned above, OWL is not currently used by CG386.
1363 OWL provides set of useful functions for creating ELF object files. These
1364 functions cover sections, symbols, and relocations. For understanding OWL, one
1365 can examine $OWROOT/bld/cg/risc/c/rscobj.c.
1367 For example, void OWLEmitReloc( owl_section_handle section, owl_offset offset,
1368 owl_symbol_handle sym, owl_reloc_type type ) is intended to add new relocation
1369 to the specified section. Relocation type is defined in OWL terms:
1371 $OWROOT/bld/owl/h/owl.h
1373 typedef enum {
1374   OWL_RELOC_ABSOLUTE,       // ref to a 32-bit absolute address
1375   OWL_RELOC_WORD,           // a direct ref to a 32-bit address
1376   OWL_RELOC_HALF_HI,        // ref to high half of 32-bit address
1377   OWL_RELOC_PAIR,           // pair - used to indicate prev hi and next lo linked
1378   OWL_RELOC_HALF_LO,        // ref to low half of 32-bit address
1379   OWL_RELOC_BRANCH_REL,     // relative branch (Alpha: 21-bit; PPC: 14-bit)
1380   OWL_RELOC_BRANCH_ABS,     // absolute branch (Alpha: not used; PPC: 14-bit)
1381   OWL_RELOC_JUMP_REL,       // relative jump (Alpha: 14-bit hint; PPC: 24-bit)
1382   OWL_RELOC_JUMP_ABS,       // absolute jump (Alpha: not used; PPC:24-bit)
1383   OWL_RELOC_SECTION_OFFSET, // offset of item within it's section
1384   // meta reloc
1385   OWL_RELOC_SECTION_INDEX,  // index of section within COFF file
1386   OWL_RELOC_TOC_OFFSET,     // 16-bit offset within TOC (PPC)
1387   OWL_RELOC_GLUE,           // location of NOP for GLUE code
1388   OWL_RELOC_FP_OFFSET,      // cheesy hack for inline assembler
1389 } owl_reloc_type;
1391 These abstract types are mapped to ELF relocation types:
1393 $OWROOT/bld/owl/c/owreloc.c
1395 static Elf32_Word elfRelocTypes386[] = {
1396   R_386_NONE,
1397   R_386_32,
1398   R_386_NONE,
1399   R_386_NONE,
1400   R_386_NONE,
1401   R_386_PC32,
1402   R_386_NONE,
1403   R_386_NONE,
1404   R_386_NONE,
1405   R_386_32,
1406   R_386_32,
1407   R_386_GOT32,
1408   R_386_NONE,
1411 As shown above, OWL is intended primarily to RISC support, so many 386 ABI
1412 features are missing or incomplete.
1415 [edit]
1417 Porting Open Watcom C Compiler and Linker to Linux
1419 The porting task was originally defined as:
1421   • Add PIC support to the compiler.
1422   • Implement building of shared objects (both PIC and PDC).
1423   • Implement using of existing shared objects.
1425 This task was defined with the assumption Open Watcom is already able to build
1426 ELF files (i.e. suitable for Linux). This is almost true, but there are two
1427 problems:
1429   • Some bugs (in open_watcom_devel_1.1.7) causing problems in building ELF
1430     executables (even “Hello, world!”).
1431   • The only object file format produced by CG386 is OMF.
1433 The first problem is, of course, temporary. After fixing the mentioned bugs, it
1434 is possible to build ELF executable from OMF and ELF object files and e.g.
1435 dietlibc library.
1437 However, the second problem is more serious. It affects the perspective of PIC
1438 implementation (and therefore, building of “real” shared objects). The
1439 corresponding issues are described in the latter sections.
1441 [edit]
1443 Position-Independent Code
1445 PIC stands for Position-Independent Code. The functions in a shared library may
1446 be loaded at different addresses in different programs, so the code in the
1447 shared object must not depend on the address (or position) at which it is
1448 loaded. Fortunately, on x86 platform all jumps are PC-relative (except for the
1449 indirect ones). There are, however, some problems with:
1451   • functions exported by a shared object;
1452   • indirect function calls, i.e. (*f)();
1453   • global variables (including static ones).
1455 These problems are solved (in 386 ABI) mostly by introducing special relocation
1456 types. These relocation types are specific to ELF object files, there are no
1457 their equivalents in OMF.
1459 There are three possible workarounds:
1461   • introducing OMF extensions for PIC support;
1462   • adding ELF output to CG386 (using OWL);
1463   • writing new code generator with ELF output (based on CG386), like RISC
1464     ones.
1466 The first approach is the simplest from implementation perspective. But we will
1467 get a non-standard object file format, alien to both Linux and Windows worlds.
1468 Therefore such approach should be ommited.
1470 The third approach seems too hard to implement, since CG386 is the most complex
1471 code generator. And it seems impractical to have two branches of CG386 that
1472 differ only in the output format.
1474 So the second approach is the best option. There are three subtasks needed for
1475 PIC support:
1477   • introducing new command line switches in wcc386 (for ELF and PIC);
1478   • implementing output of ELF object files in CG386;
1479   • implementing PIC (according to 386 ABI) in CG386.
1481 Of course, changes to Open Watcom Linker are needed as well. But wlink is
1482 described in other sections. Moreover, we can use ld to build shared object
1483 from ELFs produced by wcc386.
1486 [edit]
1488 Command Line Switches
1490 There are no ELF and PIC switches in Open Watcom C Compiler. In gcc, ELF is
1491 default format of object files, and PIC generation is turned on by either -fPIC
1492 or -fpic.
1494 Since command line of wcc386 differs from gcc very much, we may follow the
1495 “Watcom style”. For ELF, perhaps the best option is -elf. The “el” prefix is
1496 free, since the “nearest” options are -ei and -em. And this choice is logical,
1497 because the option -ez stands for “generate PharLap EZ-OMF object files”.
1499 For PIC, the GNU style seems unacceptable, since “fp” prefix is intended for
1500 floating-point options. Especially, -fpi means “inline 80x87 instructions with
1501 emulation”. Like in the ELF case, simply -pic may be acceptable (however, “p”
1502 prefixes preprocessor options). As alternative, -zpic seems a good choice,
1503 since “z” groups very specific options. There is also -re switch (already
1504 implemented). This switch is mapped to POSITION_INDEPENDANT option in CG386,
1505 but nothing reasonable is performed when it is turned on.
1507 Finally, our switch should be passed from wcc386 to CG386. The interesting
1508 files are: $OWROOT/bld/cc/c/coptions.c, cgen2.c, $OWROOT/bld/cg/h/cgswitch.h,
1509 and $OWROOT/bld/cg/intel/h/cgi86swi.h. In the compiler, switches are stored in
1510 CompFlags variable. Other important variables are GenSwitches and (especially)
1511 TargetSwitches.
1513 Switches are passed to CG386 in cgen2.c:
1515 void DoCompile() {
1516   // ...
1517   cgi_info = BEInit( GenSwitches, TargetSwitches, OptSize, ProcRevision );
1518   // ...
1522 [edit]
1524 ELF Object Files
1526 Since Open Watcom already contains OWL with ELF support, it is planned to use
1527 this library in CG386. Both CG386 and OWL were described briefly in the
1528 previous sections.
1530 Many things in CG386 are rigidly bound to OMF structure. OMF output is
1531 implemented mostly in $OWROOT/bld/cg/intel/c/i86obj.c, i86esc.c, and $OWROOT/
1532 bld/cg/c/posixio.c. However, any object file format defines virtually the same
1533 objects: groups, segments, symbols, relocations, etc. The biggest conceptual
1534 difference between OMF and ELF is relocation handling. But the opposite problem
1535 was successfully solved in ORL and WLCore. So we can implement the same
1536 “mapping” approach in CG386, avoiding harmful changes to the complicated code
1537 generator.
1539 The sample trace (see section CG386) shows how OMF object file is created.
1541 Code and data (i.e. binary payload) are written by EjectLEData(). Although
1542 there are many calls of this function in the trace, data are written when the
1543 following condition is true: obj->data.used > CurrSeg->data_prefix_size.
1544 Instead of calling PutObjRec(), we will call OWLEmitData(). Note that fix-ups
1545 are written in EjectLEData() as well. So OWLEmitReloc() should be used to write
1546 relocations.
1548 Sample mapping between i86obj.c and OWL is shown below. Each entry means that
1549 we can use specified OWL function for OMF task, so there is no direct
1550 correspondence between columns.
1552                      ┌────────────────┬──────────────────┐
1553                      │ OMF            │ OWL              │
1554                      ├────────────────┼──────────────────┤
1555                      │ DefSegment()   │ OWLSectionInit() │
1556                      ├────────────────┼──────────────────┤
1557                      │ EjectImports() │ OWLEmitImport()  │
1558                      ├────────────────┼──────────────────┤
1559                      │ EjectExports() │ OWLEmitExport()  │
1560                      ├────────────────┼──────────────────┤
1561                      │ OutLabel()     │ OWLSymbolInit()  │
1562                      └────────────────┴──────────────────┘
1564 RISC object code, located in $OWROOT/bld/$OWROOT/bld/rscobj.c. can be used as a
1565 reference.
1567 Unfortunately OWL is RISC-oriented, so missing features should be added. There
1568 are some relocation types missing in the current OWL. These relocations are
1569 described in the next section. Abstract relocation types are defined in owl.h.
1570 The mapping between OWL relocations and 386 ABI is defined in owreloc.c:
1572 static Elf32_Word elfRelocTypes386[] = {
1573   R_386_NONE,
1574   R_386_32,
1575   R_386_NONE,
1576   R_386_NONE,
1577   R_386_NONE,
1578   R_386_PC32,
1579   R_386_NONE,
1580   R_386_NONE,
1581   R_386_NONE,
1582   R_386_32,
1583   R_386_32,
1584   R_386_GOT32,
1585   R_386_NONE,
1588 Since some relocations are 386-specific, the corresponding constants to both
1589 files should be added. In addition, new fixup flags are needed for the mapping
1590 between OMF-style fixups and OWL relocations. Extending fixups seems to be the
1591 hardest part of this subtask.
1593 The only remark is that OWL in open_watcom_devel_1.1.7 seemed to be under
1594 development, i.e. some features are incomplete.
1597 [edit]
1599 PIC Generation
1601 GOT base register
1603 The EBX register serves as the global offset table base register for
1604 position-independent code. So this register should be excluded from normal code
1605 generation.
1607 Register macros were described in CG386 section. The following template
1608 illustrates turning off EBX.
1610 $OWROOT/bld/cg/intel/386/c/386rgtbl.c
1612 /************************************
1613   return the set of register which may not be modified within this routine
1614  */
1615 extern hw_reg_set FixedRegs() {
1616   hw_reg_set fixed;
1617   // ...
1618   HW_CTurnOn( fixed, HW_EBX ); // PIC
1619   return( fixed );
1622 /***************************************
1623   return the set of all registers that could be used to cache values
1624  */
1625 extern hw_reg_set AllCacheRegs() {
1626   hw_reg_set all;
1627   // ...
1628   HW_CTurnOff( all, HW_EBX ); // PIC
1629   return( all );
1633 Position-Independent Function Prologue
1635 prologue:
1636       pushl %ebp
1637       movl %esp, %ebp
1638       subl $80, %esp
1639       pushl %edi
1640       pushl %esi
1641       pushl %ebx
1642       call .L1
1643 .L1:  popl %ebx
1644       addl $_GLOBAL_OFFSET_TABLE_+[.-.L1], %ebx
1646 The call instruction pushes the absolute address of the next instruction onto
1647 the stack.
1649 Consequently, the popl instruction pops the absolute address of .L1 into
1650 register %ebx.
1652 The last instruction computes the desired absolute value into %ebx. This works
1653 because _GLOBAL_OFFSET_TABLE_ in the expression gives the distance from the
1654 addl instruction to the global offset table; [.-.L1] gives the distance from
1655 .L1 to the addl instruction. Adding their sum to the absolute address of .L1,
1656 already in %ebx, gives the absolute address of the global offset table.
1658 The last line seems a bit complicated, since there is address calculation. But
1659 actually this line should be add $0x3,%ebx, where immediate is the explicit
1660 addend for R_386_GOTPC relocation. Note that code generator should create the
1661 undefined symbol _GLOBAL_OFFSET_TABLE_, if R_386_GOTPC encountered.
1663 Prologues are handled in $OWROOT/bld/cg/intel/c/i86proc.c, so needed code
1664 should be added to void GenProlog( void ).
1666 Template:
1668 pointer lbl;
1669 // ...
1670 AllocStack();
1671 AdjustPushLocals();
1672 // PIC
1673 lbl = AskForNewLabel();
1674 GenCallLabel( lbl );
1675 CodeLabel( lbl, 0 );
1676 QuickSave( HW_EBX, OP_POP );
1677 GenRegAdd( HW_EBX, 3 );
1678 // Add relocation R_386_GOTPC
1679 GenKillLabel( lbl );
1680 ///PIC
1682 In addition, register EBX should be saved in the stack. There is variable
1683 to_push in GenProlog(), so the needed code is: HW_CTurnOn( to_push, HW_EBX ).
1685 Moreover, 386 ABI notes that EBX, ESI, and EDI should be saved in the stack,
1686 for both PIC and PDC.
1688 Of course, PIC actions depend on CG386 switch for PIC. So conditional
1689 processing as well should be also added.
1691 Position-Independent Function Epilogue
1693 All registers previously saved in stack (see above) should be restored.
1695 Although epilogue is created in void GenEpilog( void ), the interesting
1696 function is void DoEpilog( void ). Both are defined in $OWROOT/bld/cg/intel/c/
1697 i86proc.c.
1699 There is variable to_pop, defining the register set to be popped.
1702 PIC Function Calls
1704 Function calls are handled in $OWROOT/bld/cg/intel/c/i86call.c. There is also
1705 important function void AddCallIns( instruction *ins, cn call ) located in
1706 $OWROOT/bld/cg/c/bldcall.c.
1708 Since ELF-specific relocations are not implemented yet, there is no code
1709 template. However, the task is simple. For PDC, the target address has
1710 R_386_PC32 relocation. For PIC, this relocation should be R_386_PLT32. The
1711 corresponding GNU assembler line is call function@PLT.
1713 The information above covers direct function calls. Indirect function calls are
1714 kind of PIC data access described below.
1717 PIC Data Access
1719 This task covers accessing the global data (including extern and static).
1720 Position-independent instructions cannot contain absolute addresses. Instead,
1721 instructions that reference symbols hold the symbols’ offsets into the global
1722 offset table. Combining the offset with the global offset table address in EBX
1723 gives the absolute address of the table entry holding the desired address.
1725   ┌──────────────────┬───────────────────────┬─────────────────────────────┐
1726   │      Sample      │          PDC          │             PIC             │
1727   ├──────────────────┼───────────────────────┼─────────────────────────────┤
1728   │                  │                       │ .globl  src, dst, ptr       │
1729   │                  │ .globl  src, dst, ptr │                             │
1730   │ extern int src;  │                       │                             │
1731   │ extern int dst;  │                       │ movl    ptr@GOT(%ebx), %eax │
1732   │ extern int *ptr; │ movl    $dst, ptr     │ movl    dst@GOT(%ebx), %edx │
1733   │ ptr = &dst;      │                       │ movl    %edx, (%eax)        │
1734   │                  │                       │                             │
1735   │                  │                       │ movl    ptr@GOT(%ebx), %eax │
1736   │                  │ movl    ptr, %eax     │ movl    (%eax), %eax        │
1737   │ *ptr = src;      │ movl    src, %edx     │ movl    src@GOT(%ebx), %edx │
1738   │                  │ movl    %edx, (%eax)  │ movl    (%edx), %edx        │
1739   │                  │                       │ movl    %edx, (%eax)        │
1740   └──────────────────┴───────────────────────┴─────────────────────────────┘
1742 Although references like name@GOT seem complicated, their meaning is simple,
1743 e.g. mov 0x0(%ebx), %eax, where 0x0 is addend for relocation R_386_GOT32,
1744 associated with symbol ptr. For PDC, relocation type is R_386_32, and generated
1745 code is much simpler.
1747 Finally, position-independent references to static data may be optimized.
1748 Because EBX holds a known address, the global offset table, a program may use
1749 it as a base register. External references should use the global offset table
1750 entry, because dynamic linking may bind the entry to a definition outside the
1751 current object file’s scope. For static variables, the PIC code will be the
1752 following:
1754 leal ptr@GOTOFF(%ebx), %eax
1755 leal dst@GOTOFF(%ebx), %edx
1756 movl %edx, (%eax)
1757 movl ptr@GOTOFF(%ebx), %eax
1758 movl src@GOTOFF(%ebx), %edx
1759 movl %edx, (%eax)
1761 Again, references name@GOTOFF actually correspond to relocations R_386_GOTOFF,
1762 where relocation symbol is the segment (e.g. .bss), and implicit addend is
1763 offset of name in this segment.
1765 There is no code template for data access. This task is most complicated, so
1766 additional investigation is needed. PIC data access might affect the common
1767 code generator (not only CG386). In general, PIC global variable should be
1768 treated as pointer to the actual address instead of address itself.
1770 One potentially useful function is AddGlobalIndex() located in $OWROOT/bld/cg/
1771 intel/386/c/386opseg.c. This function adds EBX to every memory reference.
1774 Summary
1776 For PIC support, code generator should be able to produce some specific
1777 relocations (in addition to R_386_32 and R_386_PC32). These relocations are
1778 summarized below (now from the perspective of link editor).
1780 ┌──────────────┬──────────────────────────────────────────────────────────────┐
1781 │              │ This relocation type computes the distance from the base of  │
1782 │ R_386_GOT32  │ the global offset table to the symbol’s global offset table  │
1783 │              │ entry. It additionally instructs the link editor to build a  │
1784 │              │ global offset table.                                         │
1785 ├──────────────┼──────────────────────────────────────────────────────────────┤
1786 │              │ This relocation type computes the difference between a       │
1787 │ R_386_GOTOFF │ symbol’s value and the address of the global offset table.   │
1788 │              │ It additionally instructs the link editor to build the       │
1789 │              │ global offset table.                                         │
1790 ├──────────────┼──────────────────────────────────────────────────────────────┤
1791 │              │ This relocation type resembles R_386_PC32, except it uses    │
1792 │              │ the address of the global offset table in its calculation.   │
1793 │ R_386_GOTPC  │ The symbol referenced in this relocation normally is         │
1794 │              │ _GLOBAL_OFFSET_TABLE_, which additionally instructs the link │
1795 │              │ editor to build the global offset table.                     │
1796 ├──────────────┼──────────────────────────────────────────────────────────────┤
1797 │              │ This relocation type computes the address of the symbol’s    │
1798 │ R_386_PLT32  │ procedure linkage table entry and additionally instructs the │
1799 │              │ link editor to build a procedure linkage table.              │
1800 └──────────────┴──────────────────────────────────────────────────────────────┘
1802 Notes
1804 The information presented in the sections above should not be treated as
1805 retelling of 386 ABI. It should be used together with ABI documentation. Some
1806 details are omitted. During the porting work, developer should refer to ABI and
1807 other documentation; perform analysis using objdump and readelf; etc.
1810 [edit]
1812 Building Shared Objects
1814 This section describes the changes to Open Watcom Linker, needed for building
1815 shared libraries (PIC and PDC).
1817 [edit]
1819 Linker Command Line
1821 Fortunately, the command line option for building a shared object is already
1822 implemented in Open Watcom Linker. In such case, one should execute the linker
1823 this way: wlink form ELF DLL ...
1825 DLL stands for Dynamic Linking Library that is shared object in the Linux
1826 world. One can check that ELF shared object was requested by examining FmtData:
1828 if( (FmtData.type & MK_ELF) && FmtData.dll ) {
1829   // Do something...
1832 [edit]
1834 ELF Header
1836 Currently, LoadELF is able to produce only executable files (ET_EXEC). Shared
1837 objects have type ET_DYN. The following change is needed:
1839 $OWROOT/bld/wl/c/loadelf.c
1841 static void SetHeaders( ElfHdr *hdr ) {
1842   // ...
1843   hdr->eh.e_type = FmtData.dll ? ET_DYN : ET_EXEC;
1844   // ...
1847 [edit]
1849 Segments and Sections
1851 This is only a sample. Coding tasks are described in latter sections.
1853 ELF executables created by wlink are organized in the following way (output
1854 from readelf -a):
1856 Program Headers:
1858 Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
1859 PHDR 0x000034 0x08048034 0x00000000 0x????? 0x????? R E 0
1860 LOAD 0x?????? 0x080????? 0x00000000 0x????? 0x????? R E 0x1000
1861 LOAD 0x?????? 0x080????? 0x00000000 0x????? 0x????? RW 0x1000
1863 Section to Segment mapping:
1865 Segment Sections...
1867 01 .text
1868 02 .data .bss
1870 Shared objects created by ld are organized in the following way (complete
1871 example):
1873 Program Headers:
1875 Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
1876 LOAD 0x000000 0x00000000 0x00000000 0x????? 0x????? R E 0x1000
1877 LOAD 0x?????? 0x???????? 0x???????? 0x????? 0x????? RW 0x1000
1878 DYNAMIC 0x?????? 0x???????? 0x???????? 0x????? 0x????? RW 0x4
1880 Section to Segment mapping:
1882 Segment Sections...
1883 00 .hash .dynsym .dynstr .rel.dyn .rel.plt .plt .text .rodata
1884 01 .data .dynamic .got .bss
1885 02 .dynamic
1887 We will refer to these samples from other sections of this document.
1890 [edit]
1892 Program Headers
1894 Unnecessary PT_PHDR
1896 Since shared object is not a program, the program header entry PT_PHDR is not
1897 needed. Program headers are allocated in SetHeaders(), and the first element is
1898 always PT_PHDR.
1900 Template:
1902 static void SetHeaders( ElfHdr *hdr ) {
1903   hdr->eh.e_phnum = NumGroups + (FmtData.dll ? 0 : 1);
1904   // ...
1905   if( !FmtData.dll ) {
1906     hdr->ph->p_type = PT_PHDR;
1907     hdr->ph->p_offset = sizeof(Elf32_Ehdr);
1908     hdr->ph->p_vaddr = sizeof(Elf32_Ehdr) + FmtData.base;
1909     hdr->ph->p_paddr = 0;
1910     hdr->ph->p_filesz = hdr->ph_size;
1911     hdr->ph->p_memsz = hdr->ph_size;
1912     hdr->ph->p_flags = PF_R | PF_X;
1913     hdr->ph->p_align = 0;
1914   }
1915   // ...
1918 But PT_PHDR is assumed in WriteELFGroups(), so that function should be changed
1919 as well: ph = hdr->ph + (FmtData.dll ? 0 : 1).
1922 Necessary PT_DYNAMIC
1924 Although PT_PHDR is never used in shared objects, PT_DYNAMIC is always used
1925 there. This program header specifies dynamic linking information.
1927 Therefore we can leave hdr->eh.e_phnum = NumGroups + 1, for executable and
1928 shared object. Following the GNU convention, we will place dynamic segment
1929 after other segments.
1932 [edit]
1934 Dynamic Section
1936 The PT_DYNAMIC segment contains the .dynamic section. This section (with type
1937 SHT_DYNAMIC) contains an array of the following structures.
1939 $OWROOT/bld/watcom/h/exeelf.h
1941 typedef struct {
1942   Elf32_Sword d_tag;
1943   union {
1944     Elf32_Word d_val;
1945     Elf32_Addr d_ptr;
1946   } d_un;
1947 } Elf32_Dyn;
1949 // dynamic array tags
1951 #define DT_NULL 0
1952 #define DT_NEEDED 1 // name of a needed library
1953 #define DT_PLTRELSZ 2 // size of reloc entries for PLT
1954 #define DT_PLTGOT 3 // address with PLT or GOT
1955 #define DT_HASH 4 // symbol hash table address
1956 #define DT_STRTAB 5 // string table address
1957 #define DT_SYMTAB 6 // symbol table address
1958 #define DT_RELA 7 // address of reloc table with addends
1959 #define DT_RELASZ 8 // size of the DT_RELA table
1960 #define DT_RELAENT 9 // size of a DT_RELA entry
1961 #define DT_STRSZ 10 // size of the string table
1962 #define DT_SYMENT 11 // size of a symbol table entry
1963 #define DT_SONAME 14 // shared object name
1964 #define DT_REL 17 // address of reloc table without addends
1965 #define DT_RELSZ 18 // size of the DT_REL table
1966 #define DT_RELENT 19 // size of a DT_REL entry
1967 #define DT_PLTREL 20 // type of reloc entry for PLT
1968 #define DT_DEBUG 21 // for debugging information
1969 #define DT_JMPREL 23 // reloc entries only with PLT
1971 This section should reside in the data segment. We can create this section at
1972 the end of first linker pass (as segment in DGROUP). This section will be
1973 written later using LoadELF. Additionally, the program header PT_DYNAMIC should
1974 be updated.
1977 [edit]
1979 Dynamic Symbols
1981 Shared objects contain two symbol tables (i.e. sections): normal symbol table
1982 (SHT_SYMTAB), and dynamic symbol table (SHT_DYNSYM). The name of dynamic symbol
1983 table is .dynsym instead of .symtab.
1985 Both are generally the same, but dynamic table does not contain local symbols
1986 (except sections). Of course, the corresponding string table should be created
1987 (.dynstr instead of .strtab). For shared objects, section .hash is related to
1988 dynamic symbol table.
1990 Some changes are needed to WriteElfSymTable(), located in loadelf2.c. Function
1991 WriteSHStrings() from loadelf.c should be changed as well. These changes
1992 include providing virtual addresses of the corresponding sections (there is no
1993 memory allocation for normal symbol table), and supporting different section
1994 names and types. Like normal symbol table, two variables are needed for dynamic
1995 table:
1997 $OWROOT/bld/wl/h/loadelf.c
1999 static stringtable SymStrTab;
2000 static ElfSymTable * ElfSymTab;
2001 static stringtable DynStrTab;   // new
2002 static ElfSymTable * DynSymTab; // new
2004 The corresponding changes are needed to void InitSections( ElfHdr *hdr ) (i.e.
2005 allocating .dynsym and .dynstr), and to void ChkElfData( void ) (i.e.
2006 initializing dynamic symbol table). ELF handle should be modified as well:
2008 $OWROOT/bld/wl/h/loadelf2.h
2010 typedef struct {
2011   Elf32_Ehdr eh;
2012   // ...
2013   stringtable secstrtab;
2014   struct {
2015     int secstr;   // Index of strings section for section names
2016     int grpbase;  // Index base for Groups in section
2017     int grpnum;   // Number of groups
2018     int relbase;  // Index base for relocation sections
2019     int relnum;   // number of relocations
2020     int symstr;   // Index of symbol's string table
2021     int symtab;   // Index of symbol table
2022     int symhash;  // Index of symbol hash table
2023     int dynsym;   // Index of dynamic symbol's string table
2024     int dynstr;   // Index of dynamic symbol table
2025     int dbgbegin; // Index of first debug section
2026     int dbgnum;   // Number of debug sections
2027   } i;              // Indexes into sh
2028   unsigned_32 curr_off;
2029 } ElfHdr;
2031 Finally, the dynamic array should be updated (i.e. DT_HASH, DT_STRTAB,
2032 DT_SYMTAB, DT_STRSZ, and DT_SYMENT).
2035 [edit]
2037 Dynamic Relocations
2039 Relocations are written using WriteRelocsSections(). However, a shared object
2040 should contain single relocation table .rel.dyn. So the new function, say
2041 WriteDynRelocsSection(), is needed. This function should merge all relocations
2042 into single table. It should update .dynamic section as well (i.e. either
2043 DT_RELA, DT_RELASZ, DT_RELAENT or DT_REL, DT_RELSZ, DT_RELENT). Note that the
2044 current implementation of WriteRelocsSections() generates only “rela”
2045 relocations (i.e. explicit addend).
2047 Template
2049 // Initialize sh and its fields
2050 // ...
2051 AddSecName( hdr, sh, ".rela.dyn" );
2052 for( group = Groups; group != NULL; group = group->next_group ) {
2053   relocs = group->g.grp_relocs;
2054   if( relocs != NULL ) {
2055     size = RelocSize( relocs );
2056     sh->sh_size += size;
2057     DumpRelocList( relocs );
2058     hdr->curr_off += size;
2059   }
2060   currgrp++;
2063 // Update the dynamic array
2064 // ...
2067 [edit]
2069 Global Offset Table
2071 When link editor encounters one of the following relocation types:
2073   • R_386_GOT32
2074   • R_386_GOTOFF
2075   • R_386_GOTPC
2077 it should build the Global Offset Table. Additionally wlink should process this
2078 relocation types according to 386 ABI.
2080 GOT is defined as Elf32_Addr _GLOBAL_OFFSET_TABLE_[].
2082 The table’s entry zero is reserved to hold the address of the dynamic
2083 structure, referenced with the symbol _DYNAMIC. Entries one and two in the
2084 global offset table also are reserved.
2086 One should add support of these relocation types to both ORL and WLCore. For
2087 ORL, introduce new constants in orlglobl.h, e.g.: ORL_RELOC_TYPE_GOT_32,
2088 ORL_RELOC_TYPE_GOT_OFF, ORL_RELOC_TYPE_GOT_REL. Then extend the mapping between
2089 ELF and ORL (elflwlv.c).
2091 Then the mapping between ORL_ and FIX_ should be added to DoReloc(), objorl.c.
2092 Of course, new FIX_ constants are needed as well (obj2supp.h).
2094 Relocation processing is performed in obj2supp.c. Some preprocessing is
2095 performed in objorl.c as well.
2097 Relocation types mentioned above are processed in the following way.
2099 A - This means the addend used to compute the value of the relocatable field.
2101 G - This means the offset into the global offset table at which the address of
2102 the relocation entry’s symbol will reside during execution.
2104 GOT - This means the address of the global offset table.
2106 S - This means the value of the symbol whose index resides in the relocation
2107 entry.
2109                         ┌───────────────┬─────────────┐
2110                         │ R_386_GOT32   │ G + A - P   │
2111                         ├───────────────┼─────────────┤
2112                         │ R_386_GOTOFF  │ S + A - GOT │
2113                         ├───────────────┼─────────────┤
2114                         │ R_386_GOTPC   │ GOT + A - P │
2115                         └───────────────┴─────────────┘
2117 As shown in the table, R_386_GOT32 and R_386_GOTPC are processed very close to
2118 R_386_PC32 (S + A - P). This mean both are FIX_OFFSET_32 | FIX_REL. Similarly,
2119 R_386_GOTOFF should be FIX_OFFSET_32. Of course, additional FIX_ flags are
2120 needed to distinguish them for further processing in obj2supp.c.
2122 We can build the GOT during ORL conversion, i.e. in DoReloc(). During this
2123 phase, symbol offsets into the GOT are calculated.
2125 At the end of first linker pass, we can create the .got section (i.e. segment
2126 in DGROUP). At this time, _GLOBAL_OFFSET_TABLE_ symbol should be defined as
2127 well. This allows creating the GOT with minimal changes to the source code.
2129 For unresolved external symbols, GOT entries are needed as well. Linker should
2130 create R_386_GLOB_DAT relocations for such GOT entries. These relocations are
2131 associated with unresolved symbols.
2133 Another relocation type that can appear in shared object is R_386_RELATIVE. Its
2134 offset member gives a location within a shared object that contains a value
2135 representing a relative address. The dynamic linker computes the corresponding
2136 virtual address by adding the virtual address at which the shared object was
2137 loaded to the relative address. Such relocations are created from R_386_GOT32,
2138 if the corresponding symbol is not external.
2140 In this section, only GOT aspects related with data were described. Code
2141 aspects are described in the next section.
2143 Finally, the dynamic array should be updated (PLTGOT).
2145 Note that there is PowerPC TOC implementation in Open Watcom Linker. TOC is
2146 close to GOT in some sense, but in general it is different thing. However,
2147 developer should take a look at existing TOC implementation, since it contains
2148 some useful ideas.
2151 [edit]
2153 Procedure Linkage Table
2155 PLT is like GOT in some sense, but it is associated with PIC code instead of
2156 PIC data. Although 386 ABI defines PLT for PDC and PIC, only PIC PLT is needed
2157 for our current task:
2159 .PLT0: pushl 4(%ebx)
2160        jmp *8(%ebx)
2161        nop; nop
2162        nop; nop
2164 .PLT1: jmp *name1@GOT(%ebx)
2165        pushl $offset
2166        jmp .PLT0@PC
2168 .PLT2: jmp *name2@GOT(%ebx)
2169        pushl $offset
2170        jmp .PLT0@PC
2173 .PLT0@PC in each entry means the distance between the corresponding jmp and
2174 .PLT0, since x86 jumps are PC-relative.
2176 The GOT entry should be created for each PLT entry. Such GOT entry should
2177 contain the address of the following pushl instruction, not the real address of
2178 e.g. name1. Thus name1@GOT means the offset of the corresponding GOT entry.
2180 A new R_386_JUMP_SLOT relocation should be created. Its offset will specify the
2181 global offset table entry used in the previous jmp instruction. The relocation
2182 entry also contains a symbol table index, thus telling the dynamic linker what
2183 symbol is being referenced, e.g. name1. Instructions pushl $offset pushes the
2184 offset of such relocation in the PLT relocation table (rel.plt).
2186 When first creating the memory image of the program, the dynamic linker sets
2187 the second and the third entries in the global offset table to special values.
2188 Therefore these entries are reserved.
2190 Since PLT contains instruction opcodes, an implementation template is presented
2191 for advice:
2193 typedef struct pltent1 {
2194   unsigned_16 push_ins;
2195   unsigned_32 push_ofs;
2196   unsigned_16 jmp_ins;
2197   unsigned_32 jmp_ofs;
2198   unsigned_32 nops;
2199 } PLTENT1;
2201 typedef struct pltentn {
2202   unsigned_16 jmp1_ins;
2203   unsigned_32 jmp1_ofs;
2204   unsigned_8 push_ins;
2205   unsigned_32 push_ofs;
2206   unsigned_8 jmp2_ins;
2207   unsigned_32 jmp2_ofs;
2208 } PLTENTN;
2210 typedef union pltent {
2211   PLTENT1 first;
2212   PLTENTN entry;
2213 } PLTENT;
2215 typedef struct plt {
2216   unsigned nentries;
2217   PLTENT *entries;
2218 } PLT;
2220 void InitPLT ( PLT *plt ) {
2221   plt->entries = AllocMem( sizeof( PLTENT ) );
2222   plt->entries[0].first.push_ins = 0xB3FF;
2223   plt->entries[0].first.push_ofs = 0x00000004;
2224   plt->entries[0].first.jmp_ins = 0xA3FF;
2225   plt->entries[0].first.jmp_ofs = 0x00000008;
2226   plt->entries[0].first.nops = 0x90909090;
2227   plt->nentries = 1;
2230 void Add2PLT ( PLT *plt, unsigned_32 gotoff) {
2231   static unsigned_32 reloff = 0;
2232   plt->entries = ReallocMem( plt->entries, (plt->nentries + 1) * sizeof( PLTENT ) );
2233   plt->entries[plt->nentries].entry.jmp1_ins = 0xA3FF;
2234   plt->entries[plt->nentries].entry.jmp1_ofs = gotoff;
2235   plt->entries[plt->nentries].entry.push_ins = 0x68;
2236   plt->entries[plt->nentries].entry.push_ofs = reloff; reloff += sizeof( Elf32_Rel );
2237   // Add R_386_JUMP_SLOT relocation for push_ofs (somehow)...
2238   plt->entries[plt->nentries].entry.jmp2_ins = 0xE9;
2239   plt->entries[plt->nentries].entry.jmp2_ofs = -0x10 - plt->nentries * sizeof( PLTENT );
2240   plt->nentries++;
2243 When relocation R_386_PLT32 is encountered, the linker should create new PLT
2244 entry for the corresponding symbol (but only if its type is STT_FUNC). For
2245 further references to the same symbol, we will refer to the previously created
2246 PLT entry. R_386_PLT32 relocations are processed as L + A - P, where L means
2247 the place (section offset or address) of the procedure linkage table entry for
2248 a symbol, A and P were defined in the previous section. The corresponding ORL
2249 type, ORL_RELOC_TYPE_PLT_32, is already defined (but not implemented yet). This
2250 is relative type, so the mapping should include FIX_OFFSET_32 | FIX_REL. Source
2251 files and functions participating in relocation process were described in the
2252 previous section.
2254 At the end of first linker pass, we can create the .plt section (i.e. segment
2255 in AUTO group). This allows creating the PLT with minimal changes to the source
2256 code. Note that the separated relocation section (.rel.plt) is needed for PLT
2257 relocations. This relocation table should also reside in the code segment.
2259 Finally, the dynamic array should be updated (PLTRELSZ, PLTREL, and JMPREL).
2262 Notes
2264 The information presented in the sections above should not be treated as
2265 retelling of 386 ABI. It should be used together with ABI documentation. Some
2266 details are omitted, e.g. section flags for the dynamic section. During the
2267 porting work, developer should refer to ABI and other documentation; perform
2268 analysis using objdump and readelf; etc.
2270 Note that symbol types (STT_) are very important for dynamic linking tasks. For
2271 example, STT_FUNC is closely related with PLT. The current implementation (i.e.
2272 open_watcom_devel_1.1.7) sometimes loses symbol types, so such issues need to
2273 be fixed.
2276 [edit]
2278 Using Shared Objects
2280 This section describes the changes to Open Watcom Linker, needed for using
2281 existing shared libraries (PIC and PDC). Note that a shared library may use
2282 other shared libraries as well.
2284 Since many things are related to building shared libraries (which is covered in
2285 the provious sections of this document), this section is sufficiently short.
2288 [edit]
2290 Reading Shared Objects
2292 Shared object is another kind of ELF object file. ORL is able to read ELF
2293 object files. Some features related to shared objects are implemented as well.
2294 Thus wlink fails (i.e. Segmentation fault) when one tries to link a shared
2295 object. ORL should be reviewed and fixed in respective to these issues.
2297 Additionally, the linker should collect the names of shared objects for further
2298 processing (see "Needed Libraries" below). If this list is non-empty, the
2299 linker should perform some tasks described in the further sections.
2301 [edit]
2303 Program Interpreter
2305 The additional program header PT_INTERP is needed for an executable that uses
2306 shared object(s). It specifies the location and size of a null-terminated path
2307 name to invoke as an interpreter. This segment type is meaningful only for
2308 executable files (though it may occur for shared objects); it may not occur
2309 more than once in a file. If it is present, it must precede any loadable
2310 segment entry. For Linux, the program interpreter is /lib/ld-linux.so.2
2312 The needed changes in LoadELF are simple and obvious.
2314 [edit]
2316 Required Libraries
2318 The additional element of the dynamic array (i.e. .dynamic section) is needed.
2319 When the dynamic linker creates the memory segments for an object file, the
2320 dependencies (recorded in DT_NEEDED entries of the dynamic structure) tell what
2321 shared objects are needed to supply the program’s services.
2323 DT_NEEDED holds the string table offset of a null-terminated string, giving the
2324 name of a needed library. The offset is an index into the table recorded in the
2325 DT_STRTAB entry. The dynamic array may contain multiple entries with this type.
2326 These entries’ relative order is significant, though their relation to entries
2327 of other types is not.
2329 Dynamic array is described in the previous sections.
2331 [edit]
2333 Global Offset Table
2335 The GOT processing is described in previous section. If any specific relocation
2336 is encountered, the linker should resolve them and create the Global Offset
2337 Table. See also the next section.
2339 [edit]
2341 Procedure Linkage Table
2343 The PLT processing is described in previous section. If any specific relocation
2344 is encountered, the linker should resolve them and create the Procedure Linkage
2345 Table.
2347 There is, however, one important case not covered in the previous sections. If
2348 PDC shared object is needed for the program, the linker creates PDC PLT. Its
2349 format differs from PIC PLT:
2351 .PLT0: pushl got_plus_4
2352        jmp *got_plus_8
2353        nop; nop
2354        nop; nop
2356 .PLT1: jmp *name1_in_GOT
2357        pushl $offset
2358        jmp .PLT0@PC
2360 .PLT2: jmp *name2_in_GOT
2361        pushl $offset
2362        jmp .PLT0@PC
2365 Here got_plus_4 and got_plus_8 specify explicit addresses of the second and
2366 third GOT entries, respectively. Similarly, name1_in_GOT specifies address of
2367 the GOT entry for name1.
2369 Instead of implementation template (very similar to PIC one), a sample
2370 disassembly is presented:
2372 08048224 <.plt>:
2373  8048224: ff 35 b4 93 04 08   pushl 0x80493b4 ;&GOT[1]
2374  804822a: ff 25 b8 93 04 08   jmp *0x80493b8 ; GOT[2]
2375  8048230: 00 00
2376  8048232: 00 00
2377  8048234: ff 25 bc 93 04 08   jmp *0x80493bc ; GOT[3]
2378  804823a: 68 00 00 00 00      push $0x0
2379  804823f: e9 e0 ff ff ff      jmp 8048224
2380  8048244: ff 25 c0 93 04 08   jmp *0x80493c0 ; GOT[4]
2381  804824a: 68 08 00 00 00      push $0x8
2382  804824f: e9 d0 ff ff ff      jmp 8048224
2384 Notes
2386 During the porting work, developer should refer to ABI and other documentation;
2387 perform analysis using objdump and readelf; etc.
2389 Note that symbol types (STT_) are very important for dynamic linking tasks. For
2390 example, STT_FUNC is closely related with PLT. The current implementation (i.e.
2391 open_watcom_devel_1.1.7) sometimes loses symbol types, so such issues need to
2392 be fixed.
2395 [edit]
2397 Existing Problems
2399 Several problems exist in open_watcom_devel_1.1.7, more precisely, in the
2400 linker. So one is unable to make even the “Hello, world!” program.
2402 NOTE: By the time of the final revision of this document all the problems
2403 mentioned in this section were fixed in the Open Watcom Perforce depot
2404 therefore altering an estimated time requirements. (See estimation section).
2407 Support of R_386_PC32 relocations
2409 After linking, the relocated values are 4 less than they should be.
2411 Gcc, nasm, and other Linux compilers typically generate the following:
2413 e8 fc ff ff ff call somefunc
2415 (0xfffffffc is the implicit addend for R386_PC32 relocation).
2417 Watcom C typically generates the following (of course, in OMF format):
2419 e8 00 00 00 00 call somefunc
2421 $OWROOT/bld/wl/c/obj2supp.c
2423 static bool CheckSpecials( fix_data *fix, frame_spec *targ ) {
2424   . . .
2425   if( !(fix->type & FIX_REL) ) return FALSE;
2426   . . .
2427   fixsize = CalcFixupSize( fix->type );
2428   off -= fixsize;
2429   . . .
2432 This algorithm introduces our 4-byte error. Such correction isn't needed for
2433 ELF R386_PC32, since implicit addend is specified (0xfffffffc == -4).
2435 QUICK FIX: Offset correction should be disabled in case implicit addend was
2436 specified.
2438 $OWROOT/bld/wl/c/obj2supp.c
2440 static bool CheckSpecials( fix_data *fix, frame_spec *targ ) {
2441   . . .
2442   if( !(fix->type & FIX_REL) ) return FALSE;
2443   . . .
2444   fixsize = CalcFixupSize( fix->type );
2445   if( fix->type & FIX_ADDEND_ZERO ) off -= fixsize; // quickfix #01
2446   . . .
2449 NOTE. This is temporary solution. New ORL relocation type (or option) is needed
2450 for a more accurate fix. This bug was already fixed in the development source
2451 tree at the moment of writing this SRS.
2454 Support of STT_NOTYPE symbols
2456 Two of symbol types defined in ABI:
2458 STT_NOTYPE The symbol's type is not specified.
2460 STT_FUNC The symbol is associated with a function or other executable code.
2462 Many of “real-life” ELF object files has symbols of STT_NOTYPE, e.g. _start in
2463 dietlibc's start.o. When linking that sort of object files, Open Watcom Linker
2464 complains such symbols are not found. This error is fatal.
2466 ORL treats STT_NOTYPE and unknown symbol types as ORL_SYM_TYPE_NONE. This
2467 (somehow) confuses the linker.
2469 $OWROOT/bld/orl/elf/c/elflwlv.c
2471 default:
2472   current->type = ORL_SYM_TYPE_NONE; // ?
2474 QUICK FIX: If symbol's associated section (i.e. st_shndx) looks like
2475 executable, treat that symbol as ORL_SYM_TYPE_FUNCTION.
2477 $OWROOT/bld/orl/elf/c/elflwlv.c
2479 orl_return ElfCreateSymbolHandles( elf_sec_handle elf_sec_hnd ) {
2480   elf_sec_handle sym_sec; // Nick's quickfix #02
2481   . . .
2482   default:
2483     // hotfix #02
2484     if( ( sym_sec = ElfSymbolGetSecHandle( current ) ) != NULL
2485         && sym_sec->type == ORL_SEC_TYPE_PROG_BITS
2486         && sym_sec->flags & ORL_SEC_FLAG_EXEC
2487       ) {
2488         current->type = ORL_SYM_TYPE_FUNCTION;
2489     } else {
2490         current->type = ORL_SYM_TYPE_NONE;
2491     }
2493 NOTE. This workaround works pretty well for current version, but has some
2494 drawbacks in “shared libraries” perspective. When another object file
2495 references a function from a shared object, the link editor automatically
2496 creates a procedure linkage table entry for the referenced symbol. Shared
2497 object symbols with types other than STT_FUNC will not be referenced
2498 automatically through the procedure linkage table.
2500 The accurate fix should treat STT_NOTYPE as “normal” symbol.
2503 Accurate segment mapping
2505 Sections .data and .bss share the same segment in ELF executables produced by
2506 wlink. If .bss section is created, the memory size (p_memsz) of that segment
2507 became invalid. The produced ELF causes segmentation fault.
2509 readelf -a
2511 Section Headers:
2512 . . .
2513 [Nr] Name Type Addr Off Size ES Flg Lk Inf Al
2514 [ 2] .text PROGBITS 08048100 000100 00103d 00 AX 0 0 4
2515 [ 3] .data PROGBITS 0804a000 002000 000288 00 WA 0 0 4
2516 [ 4] .bss NOBITS 0804b000 003000 0000b4 00 WA 0 0 4
2517 . . .
2519 Program Headers:
2521 Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
2522 PHDR 0x000034 0x08048034 0x00000000 0x00060 0x00060 R E 0
2523 LOAD 0x000100 0x08048100 0x00000000 0x0103d 0x0103d R E 0x1000
2524 LOAD 0x002000 0x0804a000 0x00000000 0x00288 0x000c4 RW 0x1000
2526 Section to Segment mapping:
2528 Segment Sections...
2530 01 .text
2533 It seems page alignment is not taken into account when .bss section is created.
2535 QUICK FIX: p_memsz should be adjusted after creating the .bss.
2537 $OWROOT/bld/wl/c/loadelf.c
2539 InitBSSSect( sh, off, CalcSplitSize(), linear );
2540 ph->p_memsz += ROUND_UP( ph->p_filesz, FmtData.objalign ); // quickfix #03
2542 readelf -a
2544 Section Headers:
2546 [Nr] Name Type Addr Off Size ES Flg Lk Inf Al
2547 . . .
2548 [ 2] .text PROGBITS 08048100 000100 00103d 00 AX 0 0 4
2549 [ 3] .data PROGBITS 0804a000 002000 000288 00 WA 0 0 4
2550 [ 4] .bss NOBITS 0804b000 003000 0000b4 00 WA 0 0 4
2551 . . .
2553 Program Headers:
2555 Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
2556 PHDR 0x000034 0x08048034 0x00000000 0x00060 0x00060 R E 0
2557 LOAD 0x000100 0x08048100 0x00000000 0x0103d 0x0103d R E 0x1000
2558 LOAD 0x002000 0x0804a000 0x00000000 0x00288 0x010c4 RW 0x1000
2560 Section to Segment mapping:
2562 Segment Sections...
2564 01 .text
2565 02 .data .bss
2567 NOTE. This workaround works well enough, but the problem should be revised.
2568 More accurate fix is required.
2571 [edit]
2573 Estimation
2575 There are two independent tasks: Code Generator (PIC support) and Linker
2576 (building and using shared objects). So it is possible to perform these tasks
2577 simultaneously. GNU C Compiler can be used for Linker testing, as well as ld
2578 for Code Generator. Then the final integration (i.e. testing) should be
2579 performed, using only Open Watcom tools.
2581 Position-Independent Code
2583 Command line processing
2585 Estimation: 1 day
2587 Description: see section 3.1.1
2589 Extending OWL
2591 Estimation: 8 days
2593 Description: see section 3.1.2
2595 Implementing ELF output in CG386
2597 Estimation: 20 days
2599 Description: see section 3.1.2. This is pretty complicated task. No PIC support
2600 yet (see below).
2602 Adding PIC support to CG386
2604 Estimation: 20 days
2606 Description: see section 3.1.3. This is one of most complicated tasks.
2608 Extending ELF output in CG386
2610 Estimation: 5 days
2612 Description: see sections 3.1.2, 3.1.3. This task means adding PIC features to
2613 ELF.
2615 Integration
2617 Estimation: 5 days
2619 Description: Mostly testing. Complicated test kit (i.e. C source code) is
2620 needed to ensure all things are implemented correctly.
2622 Total 59 days
2625 Building Shared Objects
2627 Extending ORL
2629 Estimation: 3 days
2631 Description: see section 3.2.7
2633 Extending WLCore
2635 Estimation: 15 days
2637 Description: see sections 3.2.7, 3.2.8, 3.2.9
2639 Improving LoadELF
2641 Estimation: 5 days
2643 Description: see sections 3.2.1 – 3.2.9
2645 Integration
2647 Estimation: 4 days
2649 Description: Mostly testing. Complicated test kit (i.e. object files) is needed
2650 to ensure all things are implemented correctly.
2652 Total 27 days
2655 Using Shared Objects
2657 Command line processing
2659 Estimation: 1 day
2661 Description: see section 3.3.3
2663 Improving LoadELF
2665 Estimation: 1 day. Minimal changes are needed (assuming we are already able to
2666 build a shared object).
2668 Description: see sections 3.3.2, 3.3.3
2670 Extending ORL
2672 Estimation: 10 days
2674 Description: see section 3.3.1
2676 Extending WLCore
2678 Estimation: 8 days
2680 Description: see sections 3.3.4, 3.3.5
2682 Integration
2684 Estimation: 10 days
2686 Description: Mostly testing. Complicated test kit (i.e. object files) is needed
2687 to ensure all things are implemented correctly. There are many variants, e.g.
2688 executable uses three shared objects, where the 1st shared object uses the 2nd,
2689 and the 3rd uses some another shared object.
2691 Total 30 days
2694 Final Integration
2696 Estimation: 10 days
2698 Description: Mostly testing. Trying to link ELF object files (i.e. those
2699 generated by Open Watcom C) using Open Watcom Linker.
2701 Retrieved from "http://www.openwatcom.org/index.php/Linux_Port"
2703 Categories: Linux | Projects
2705 Views
2707   • Article
2708   • Discussion
2709   • Edit
2710   • History
2712 Personal tools
2714   • Log in / create account
2718 Navigation
2720   • Main Page
2721   • User Resources
2722   • Contributor Resources
2723   • Popular Pages
2724   • Web Changes
2725   • Online Source
2726   • Bugzilla
2727   • Help
2728   • Donations
2730 Search
2732 [                    ] [Go]  [Search]
2733 Toolbox
2735   • What links here
2736   • Related changes
2737   • Upload file
2738   • Special pages
2739   • Printable version
2740   • Permanent link
2742 MediaWiki
2743 Attribution 2.5
2745   • This page was last modified 02:38, 23 October 2006.
2746   • This page has been accessed 28,612 times.
2747   • Content is available under Attribution 2.5.
2748   • Privacy policy
2749   • About Open Watcom
2750   • Disclaimers