This source PF generates EuroAssembler output object file in program format COFF, as specified in [MS_PECOFF].
EUROASM NOWARN=2101,NOWARN=2102
pfcoff PROGRAM FORMAT=COFF,MODEL=FLAT,WIDTH=32
INCLUDEHEAD euroasm.htm, \ Interface (structures, symbols and macros) of other modules used in this source.
ea.htm,eaopt.htm,exp.htm,msg.htm,pf.htm,pfpe.htm,pgm.htm,pgmopt.htm,reloc.htm,sss.htm,stm.htm,sym.htm
pfcoff HEAD ; Start module interface.
PFCOFF_FILE_HEADER STRUC .Machine D WORD ; See PFCOFF_encodings below. .NumberOfSections D WORD ; How many PFCOFF_SECTION_HEADER objects follow the file header. .TimeDateStamp D DWORD ; Seconds since 1.1.1970 UTC till the link time. .PointerToSymbolTable D DWORD ; File offset of COFF symbol table, or 0 if the table is omitted. .NumberOfSymbols D DWORD ; How many PFCOFF_SYMBOL objects there are in symbol table. .SizeOfOptionalHeader D WORD ; Size of PFPE_OPTIONAL_HEADER32 object including .DataDirectory. .Characteristics D WORD ; See PFCOFF_encodings below. ENDSTRUC PFCOFF_FILE_HEADER ; SIZE# PFCOFF_FILE_HEADER=14h=20
PFCOFF_SECTION_HEADER STRUC .Name D 8*BYTE ; Section name, NULL padded but not always NULL terminated. Or /123 (offset in string table). .VirtualSize D DWORD ; Aligned section size (PE|DLL]. 0 in object files (COFF). .VirtualAddress D DWORD ; RVA of section relative to ImageBase when loaded in memory. 0 in object files. .SizeOfRawData D DWORD ; Rounded up by FileAlignment in PE|DLL. 0 in BSS sections. .PointerToRawData D DWORD ; File pointer to section data. Rounded up to FileAlignment in executables. 0 in BSS. .PointerToRelocations D DWORD ; File pointer to relocation entries for this section. 0 if no relocations. .PointerToLinenumbers D DWORD ; File pointer to line-number entries for this section. 0 if no line numbers. .NumberOfRelocations D WORD ; Number of relocation entries for this section. .NumberOfLinenumbers D WORD ; Number of line-number entries for this section. Not supported by €ASM. .Characteristics D DWORD ; See PFCOFF_encodings below. ENDSTRUC PFCOFF_SECTION_HEADER ; SIZE# PFCOFF_SECTION_HEADER=28h=40
PFCOFF_RELOCATION is a 10 byte structure of objects which are stored in the table immediately following raw data in each section of COFF object file, independed of module width.
Assignment of the .Type member of PFCOFF_RELOCATION depends on the architecture, which is selected in €ASM by PFCOFF_FILE_HEADER.Machine, which is selected by the width of COFF module file:
| .Type value | MS SDK nomenclature | Remark | €ASM RELOC.Type |
|---|---|---|---|
| 0x0000 | IMAGE_REL_I386_ABSOLUTE | Reference is absolute, no relocation is necessary | relocResolved |
| 0x0001 | IMAGE_REL_I386_DIR16 | Direct 16-bit reference to the symbols virtual address | relocAbsVA + relocWidth16 |
| 0x0002 | IMAGE_REL_I386_REL16 | IP-relative 16-bit reference to the symbols virtual address | relocRel + relocWidth16 |
| 0x0006 | IMAGE_REL_I386_DIR32 | Direct 32-bit reference to the symbols virtual address | relocAbsVA + relocWidth32 |
| 0x0007 | IMAGE_REL_I386_DIR32NB | Direct 32-bit reference to the symbols virtual address, base not included | relocAbsRVA + relocWidth32 |
| 0x0009 | IMAGE_REL_I386_SEG12 | Direct 16-bit reference to the segment-selector bits of a 32-bit virtual address | relocPara + relocWidth16 |
| 0x000A | IMAGE_REL_I386_SECTION | The 16-bit section index of the section that contains the target. This is used to support debugging information. | not supported |
| 0x000B | IMAGE_REL_I386_SECREL | The 32-bit offset of the target from the beginning of its section. This is used to support debugging information and static thread local storage. | not supported |
| 0x000C | IMAGE_REL_I386_TOKEN | CLR token | not supported |
| 0x000D | IMAGE_REL_I386_SECREL7 | 7 bit offset from base of section containing target | not supported |
| 0x0014 | IMAGE_REL_I386_REL32 | EIP-relative 32-bit reference to the symbols virtual address | relocRel + relocWidth32 |
| .Type value | MS SDK nomenclature | Remark | €ASM RELOC.Type |
|---|---|---|---|
| 0x0000 | IMAGE_REL_AMD64_ABSOLUTE | Reference is absolute, no relocation is necessary | relocResolved |
| 0x0001 | IMAGE_REL_AMD64_ADDR64 | The 64-bit VA of the relocation target. | relocAbsVA + relocWidth64 |
| 0x0002 | IMAGE_REL_AMD64_ADDR32 | The 32-bit VA of the relocation target. | relocAbsVA + relocWidth32 |
| 0x0003 | IMAGE_REL_AMD64_ADDR32NB | The 32-bit address without an image base (RVA). | relocAbsRVA + relocWidth32 |
| 0x0004 | IMAGE_REL_AMD64_REL32 | The 32-bit relative address from the byte following the relocation. | relocRel + relocWidth32 |
| 0x0005 | IMAGE_REL_AMD64_REL32_1 | The 32-bit address RIP-relative to byte distance 1 from the relocation. | relocRel + relocWidth32 + 1<<12 |
| 0x0006 | IMAGE_REL_AMD64_REL32_2 | The 32-bit address RIP-relative to byte distance 2 from the relocation. | relocRel + relocWidth32 + 2<<12 |
| 0x0007 | IMAGE_REL_AMD64_REL32_3 | The 32-bit address RIP-relative to byte distance 3 from the relocation. | relocRel + relocWidth32 + 3<<12 |
| 0x0008 | IMAGE_REL_AMD64_REL32_4 | The 32-bit address RIP-relative to byte distance 4 from the relocation. | relocRel + relocWidth32 + 4<<12 |
| 0x0009 | IMAGE_REL_AMD64_REL32_5 | The 32-bit address RIP-relative to byte distance 5 from the relocation. | relocRel + relocWidth32 + 5<<12 |
| 0x000A | IMAGE_REL_AMD64_SECTION | The 16-bit section index of the section that contains the target. This is used to support debugging information. | not supported |
| 0x000B | IMAGE_REL_AMD64_SECREL | The 32-bit offset of the target from the beginning of its section. This is used to support debugging information and static thread local storage. | not supported |
| 0x000C | IMAGE_REL_AMD64_SECREL7 | A 7-bit unsigned offset from the base of the section that contains the target. | not supported |
| 0x000D | IMAGE_REL_AMD64_TOKEN | CLR tokens. | not supported |
| 0x000E | IMAGE_REL_AMD64_SREL32 | A 32-bit signed span-dependent value emitted into the object. | not supported |
| 0x000F | IMAGE_REL_AMD64_PAIR | A pair that must immediately follow every span-dependent value. | not supported |
| 0x0010 | IMAGE_REL_AMD64_SSPAN32 | A 32-bit signed span-dependent value that is applied at link time. | not supported |
PFCOFF_RELOCATION STRUC .VirtualAddress D DWORD ; RVA of relocated word/dword/qword in emitted code. .SymbolTableIndex D DWORD ; Zero-based index of PFCOFF_SYMBOL in the symbol table. .Type D WORD ; See the table above. ENDSTRUC PFCOFF_RELOCATION ; SIZE# PFCOFF_RELOCATION=0Ah=10
PFCOFF_LINENUMBER STRUC .VirtualAddress D 0*DWORD ; RVA related to the .LineNumber if .LineNumber > 0. Unioned with .SymbolTableIndex. .SymbolTableIndex D DWORD ; Zero-based index of PFCOFF_SYMBOL in the symbol table. .Linenumber D WORD ; Physical line number if nonzero, otherwise .SymbolTableIndex is used. ENDSTRUC PFCOFF_LINENUMBER ; SIZE# PFCOFF_LINENUMBER=6
PFCOFF_SYMBOL STRUC
.Name D 8*BYTE; Alias DD 0,OffsetIntoStringTable if the namesize is longer than 8.
.Value D DWORD ; Relocatable address or scalar value of the symbol.
.SectionNumber D WORD ; 1-based index to the table of IMAGE_SECTION_HEADERs or spec.constant in PFCOFF_encodings.
.Type D WORD ; See PFCOFF_encodings below.
.StorageClass D BYTE ; See PFCOFF_encodings below.
.NumberOfAuxSymbols D BYTE ; Number of auxiliary symbol table entries that follow this record.
ENDSTRUC PFCOFF_SYMBOL ; SIZE# PFCOFF_SYMBOL=12h=18
WINNT.h.
; PFCOFF_SECTION_HEADER.Characteristics: pfcoffSCN_CNT_CODE = 0x0000_0020 ; Section contains code. pfcoffSCN_CNT_INITIALIZED_DATA = 0x0000_0040 ; Section contains initialized data. pfcoffSCN_CNT_UNINITIALIZED_DATA = 0x0000_0080 ; Section contains uninitialized data. pfcoffSCN_PurposeMask = 0x0000_00E0 pfcoffSCN_LNK_INFO = 0x0000_0200 ; Section contains comments or some other type of information. pfcoffSCN_LNK_REMOVE = 0x0000_0800 ; Section contents will not become part of image. pfcoffSCN_LNK_COMDAT = 0x0000_1000 ; Section contents COMDAT data. pfcoffSCN_GPREL = 0x0000_8000 ; Section content can be accessed relative to global pointer. pfcoffSCN_MEM_PURGEABLE = 0x0002_0000 ; Reserved. pfcoffSCN_ALIGN_1BYTES = 0x0010_0000 ; Section alignment is BYTE. Valid only for object files. pfcoffSCN_ALIGN_2BYTES = 0x0020_0000 ; Section alignment is WORD. Valid only for object files. pfcoffSCN_ALIGN_4BYTES = 0x0030_0000 ; Section alignment is DWORD. Valid only for object files. pfcoffSCN_ALIGN_8BYTES = 0x0040_0000 ; Section alignment is QWORD. Valid only for object files. pfcoffSCN_ALIGN_16BYTES = 0x0050_0000 ; Section alignment is OWORD. Valid only for object files. Default. pfcoffSCN_ALIGN_32BYTES = 0x0060_0000 ; Section alignment is YWORD. Valid only for object files. pfcoffSCN_ALIGN_64BYTES = 0x0070_0000 ; Section alignment is ZWORD. Valid only for object files. pfcoffSCN_ALIGN_128BYTES = 0x0080_0000 ; Section alignment is 128. Valid only for object files. pfcoffSCN_ALIGN_256BYTES = 0x0090_0000 ; Section alignment is 256. Valid only for object files. pfcoffSCN_ALIGN_512BYTES = 0x00A0_0000 ; Section alignment is 512. Valid only for object files. pfcoffSCN_ALIGN_1024BYTES = 0x00B0_0000 ; Section alignment is 1K. Valid only for object files. pfcoffSCN_ALIGN_2048BYTES = 0x00C0_0000 ; Section alignment is 2K. Valid only for object files. pfcoffSCN_ALIGN_4096BYTES = 0x00D0_0000 ; Section alignment is 4K. Valid only for object files. pfcoffSCN_ALIGN_8192BYTES = 0x00E0_0000 ; Section alignment is 8K. Valid only for object files. pfcoffSCN_ALIGN_MASK = 0x00F0_0000 ; Mask for section alignment. pfcoffSCN_LNK_NRELOC_OVFL = 0x0100_0000 ; Section contains extended relocations. pfcoffSCN_MEM_DISCARDABLE = 0x0200_0000 ; Section can be discarded. pfcoffSCN_MEM_NOT_CACHED = 0x0400_0000 ; Section is not cacheable. pfcoffSCN_MEM_NOT_PAGED = 0x0800_0000 ; Section is not pageable. pfcoffSCN_MEM_SHARED = 0x1000_0000 ; Section is shareable. pfcoffSCN_MEM_EXECUTE = 0x2000_0000 ; Section is executable. pfcoffSCN_MEM_READ = 0x4000_0000 ; Section is readable. pfcoffSCN_MEM_WRITE = 0x8000_0000 ; Section is writeable. pfcoffSCN_AccessMask = 0xE000_0000 ; PFCOFF_FILE_HEADER. Machine CPU values: pfcoffFILE_MACHINE_UNKNOWN = 0x0000 ; Applicable to any machine type. pfcoffFILE_MACHINE_I386 = 0x014C ; Intel 386. Default for 16|32bit modules, regardless on CPU=. pfcoffFILE_MACHINE_I486 = 0x014D ; Intel 486. pfcoffFILE_MACHINE_I586 = 0x014E ; Intel Pentium. pfcoffFILE_MACHINE_IA64 = 0x0200 ; Intel Itanium (64bit). pfcoffFILE_MACHINE_AMD64 = 0x8664 ; AMD 64bit. Default for 64bit modules. ; PFCOFF_FILE_HEADER.Characteristics flags: pfcoffFILE_RELOCS_STRIPPED = 0x0001 ; Relocation info stripped from file. pfcoffFILE_EXECUTABLE_IMAGE = 0x0002 ; File is executable (i.e. no unresolved external references). pfcoffFILE_LINE_NUMS_STRIPPED = 0x0004 ; Line numbers stripped from file. pfcoffFILE_LOCAL_SYMS_STRIPPED = 0x0008 ; Local symbols stripped from file. pfcoffFILE_AGGRESIVE_WS_TRIM = 0x0010 ; Agressively trim working set (obsolete). pfcoffFILE_LARGE_ADDRESS_AWARE = 0x0020 ; Application can handle more than 2GB addresses - 64bit module. ; = 0x0040 ; Reserved. pfcoffFILE_BYTES_REVERSED_LO = 0x0080 ; Bytes of machine word are reversed (deprecated). pfcoffFILE_32BIT_MACHINE = 0x0100 ; 32 bit architecture. Reset in 16bit COFF. pfcoffFILE_DEBUG_STRIPPED = 0x0200 ; Debugging info stripped from image file into .DBG file. pfcoffFILE_REMOVABLE_RUN_FROM_SWAP = 0x0400 ; If image is on removable media, copy and run from the swap file. pfcoffFILE_NET_RUN_FROM_SWAP = 0x0800 ; If image is on network, copy and run from the swap file. pfcoffFILE_SYSTEM = 0x1000 ; Image is a system file rather than user program. pfcoffFILE_DLL = 0x2000 ; File is a DLL. pfcoffFILE_UP_SYSTEM_ONLY = 0x4000 ; File should only be run on a uniprocessor machine pfcoffFILE_BYTES_REVERSED_HI = 0x8000 ; Bytes of machine word are reversed (deprecated). ; PFCOFF_SYMBOL.SectionNumber special constants: pfcoffSYM_UNDEFINED = 0 ; Symbol is undefined or it is common. pfcoffSYM_ABSOLUTE = -1 ; Symbol is an absolute value (scalar). pfcoffSYM_DEBUG = -2 ; Symbol is a special debug item. ; PFCOFF_SYMBOL.StorageClass constants: pfcoffSYM_CLASS_EXTERNAL = 2 ; External or public symbol. pfcoffSYM_CLASS_STATIC = 3 ; Standard private symbol or segment. pfcoffSYM_CLASS_FILE = 103 ; Source filename symbol. pfcoffSYM_CLASS_SECTION = 104 ; Definition of section (MSCOFF uses pfcoffSYM_CLASS_STATIC instead). ; PFCOFF_SYMBOL.Type is reduced to EuroAssembler's limited set of fundamental datatypes: ; LSB Type specifies the width and type of the symbol. pfcoffSYM_TYPE_NULL = 0x00 ; No type information. pfcoffSYM_TYPE_VOID = 0x01 ; No valid type. pfcoffSYM_TYPE_CHAR = 0x02 ; BYTE. pfcoffSYM_TYPE_SHORT = 0x03 ; WORD. pfcoffSYM_TYPE_INT = 0x04 ; DWORD or QWORD (32bit or 64bit program). pfcoffSYM_TYPE_LONG = 0x05 ; DWORD. pfcoffSYM_TYPE_FLOAT = 0x06 ; DWORD. pfcoffSYM_TYPE_DOUBLE = 0x07 ; QWORD. pfcoffSYM_TYPE_BYTE = 0x0C ; BYTE. pfcoffSYM_TYPE_WORD = 0x0D ; WORD. pfcoffSYM_TYPE_UINT = 0x0E ; DWORD or QWORD (32bit or 64bit program). pfcoffSYM_TYPE_DWORD = 0x0F ; DWORD. pfcoffSYM_TYPE_LONGDOUBLE = 0x10 ; TBYTE. ; MSB Type specifies complex type of symbol. pfcoffSYM_DTYPE_NULL = 0x00 ; No derived type. pfcoffSYM_DTYPE_POINTER = 0x01 ; Pointer to base type. pfcoffSYM_DTYPE_FUNCTION = 0x02 ; Procedure or function. pfcoffSYM_DTYPE_ARRAY = 0x03 ; Structure.
ENDHEAD pfcoff ; End of module interface.
PfcoffSymFile Procedure File, SymbolTableBuffer
SymPtr LocalVar
MOV EBX,[%SymbolTableBuffer]
BufferNew EBX, SIZE# PFCOFF_SYMBOL, Zeroed=Yes ; Base record.
JC .90:
MOV [%SymPtr],EAX
MOV EDI,EAX
MOVB [EDI+PFCOFF_SYMBOL.StorageClass],pfcoffSYM_CLASS_FILE ; 103=0x67
MOVW [EDI+PFCOFF_SYMBOL.SectionNumber],pfcoffSYM_DEBUG ; -2=0xFFFE
MOV EAX,".fil"
MOV [EDI+PFCOFF_SYMBOL.Name+0],EAX
MOV AL,"e"
MOV [EDI+PFCOFF_SYMBOL.Name+4],AL
MOV ESI,[%File]
LEA EDX,[ESI+FILE.Name]
.20:BufferNew EBX, SIZE# PFCOFF_SYMBOL, Zeroed=Yes ; Auxilliary record.
JC .90:
MOV ESI,[%SymPtr] ; ESI now points to the base record.
INCB [ESI+PFCOFF_SYMBOL.NumberOfAuxSymbols]
MOV EDI,EAX ; EDI now points to the auxilliary record.
MOV ESI,EDX ; ESI now points to the unstored part of file name.
MOV ECX,SIZE# PFCOFF_SYMBOL
.30:LODSB
CMP AL,0
JZ .90:
STOSB
LOOP .30: ; Copy file name to auxilliary record(s).
MOV EDX,ESI
JMP .20:
.90:EndProcedure PfcoffSymFile
PfcoffSymSegment Procedure Symbol, SymbolTableBuffer, StringTableBuffer
; Update input Symbol.NameIndex.
BufferRetrieve [%SymbolTableBuffer]
MOV EAX,ECX ; PFCOFF_SYMBOL records used so far = index in COFF symbol table.
SUB EDX,EDX
MOV ECX, SIZE# PFCOFF_SYMBOL ; 18.
DIV ECX
MOV EDX,[%Symbol] ; EDX=^SYM.
MOV ECX,[EDX+SYM.Section]
JNSt [ECX+SSS.Status],sssSegment,.90: ; If Symbol represents a group, ignore (COFF doesn't support groups).
MOV [EDX+SYM.NameIndex],EAX
; Create new PFCOFF_SYMBOL.
BufferNew [%SymbolTableBuffer], SIZE# PFCOFF_SYMBOL, Zeroed=Yes
JC .90:
MOV EBX,EAX ; EBX=^PFCOFF_SYMBOL.
; PFCOFF_SYMBOL.Name.
MOV ECX,[EDX+SYM.NameSize]
MOV ESI,[EDX+SYM.NamePtr]
LEA EDI,[EBX+PFCOFF_SYMBOL.Name]
CMP ECX,8
JA .10:
REP MOVSB ; Symbol name is short.
JMPS .20:
.10: MOV EAX,[%StringTableBuffer] ; Symbol name is long.
PUSH ECX,ESI
BufferRetrieve EAX
MOV [EBX+PFCOFF_SYMBOL.Name+4],ECX
POP ESI,ECX
BufferStore EAX,ESI,ECX
BufferStoreByte EAX,0
.20: ; PFCOFF_SYMBOL.SectionNumber.
MOV EDX,[EDX+SYM.Section] ; EDX=^SSS.
MOV EAX,[EDX+SSS.SegmIndex]
MOV [EBX+PFCOFF_SYMBOL.SectionNumber],EAX
; PFCOFF_SYMBOL.StorageClass.
MOVB [EBX+PFCOFF_SYMBOL.StorageClass],pfcoffSYM_CLASS_STATIC ; 3.
; PFCOFF_SYMBOL auxilliary record Format 5.
MOVB [EBX+PFCOFF_SYMBOL.NumberOfAuxSymbols],1
BufferNew [%SymbolTableBuffer], SIZE# PFCOFF_SYMBOL, Zeroed=Yes
MOV EBX,EAX
BufferRetrieve [EDX+SSS.EmitBuffer]
MOV [EBX+0],ECX
BufferRetrieve [EDX+SSS.RelocBuffer]
MOV EAX,ECX
SUB EDX,EDX
MOV ECX, SIZE# RELOC
DIV ECX
MOV ECX,0xFFFF
CMP EAX,ECX
JNA .30:
XCHG EAX,ECX
.30: MOV [EBX+4],AX
.90:EndProcedure PfcoffSymSegment
Symbol.NameIndex.
PfcoffSymSymbol Procedure Symbol, SymbolTableBuffer, StringTableBuffer
; Update input Symbol.NameIndex.
BufferRetrieve [%SymbolTableBuffer]
MOV EAX,ECX ; Number of PFCOFF_SYMBOL records used so far = index in COFF symbol table.
SUB EDX,EDX
MOV ECX, SIZE# PFCOFF_SYMBOL ; 18.
DIV ECX
MOV EDX,[%Symbol] ; EDX=^SYM.
MOV [EDX+SYM.NameIndex],EAX ; Update SYM.NameIndex of the input symbol EDX.
; Create new PFCOFF_SYMBOL.
BufferNew [%SymbolTableBuffer],ECX,Zeroed=Yes; Allocate 18 bytes of memory.
JC .90:
MOV EBX,EAX ; EBX=^PFCOFF_SYMBOL.
; PFCOFF_SYMBOL.Name.
MOV ECX,[EDX+SYM.NameSize]
MOV ESI,[EDX+SYM.NamePtr]
LEA EDI,[EBX+PFCOFF_SYMBOL.Name]
CMP ECX,8
JA .10:
REP MOVSB ; Symbol name is short.
JMPS .20:
.10:MOV EAX,[%StringTableBuffer] ; Symbol name is long.
PUSH ECX,ESI
BufferRetrieve EAX
MOV [EBX+PFCOFF_SYMBOL.Name+4],ECX ; Relative address of long name.
POP ESI,ECX
BufferStore EAX,ESI,ECX ; Store long name.
BufferStoreByte EAX,0 ; Zero-terminate the name.
.20:; PFCOFF_SYMBOL.Value.
MOV EAX,[EDX+SYM.OffsetLow]
MOV [EBX+PFCOFF_SYMBOL.Value],EAX
; PFCOFF_SYMBOL.SectionNumber.
MOV AX,pfcoffSYM_UNDEFINED ; AX=0, assume external symbol.
JSt [EDX+SYM.Status],symExtern | symImport, .30:
MOV ECX,[EDX+SYM.Section]
MOV AX,pfcoffSYM_ABSOLUTE ; AX=-1, assume scalar symbol.
JECXZ .30: ; If symbol's segment is empty.
MOV EAX,[ECX+SSS.SegmIndex] ; AX=ordinal number of symbols segment.
.30:MOV [EBX+PFCOFF_SYMBOL.SectionNumber],AX
; PFCOFF_SYMBOL.StorageClass.
MOV AL,pfcoffSYM_CLASS_EXTERNAL ; AL=2, assume global symbol.
JSt [EDX+SYM.Status],symExtern | symPublic | symExport | symImport,.40:
MOV AL,pfcoffSYM_CLASS_STATIC ; AL=3, otherwise it is standard private local symbol.
.40:MOV [EBX+PFCOFF_SYMBOL.StorageClass],AL
; Symbol.Type.
MOV EAX,[EDX+SYM.Status]
MOV CX,pfcoffSYM_DTYPE_FUNCTION <<8 + pfcoffSYM_TYPE_VOID ; >> 0x2001
JSt EAX,symProc,.50: ; If the symbol EDX is PROC (procedure/function name).
Dispatch AL,'A','B','U','W','D','Q','T'
MOV CX,pfcoffSYM_DTYPE_NULL <<8 + pfcoffSYM_TYPE_NULL ; >> 0x0000 default to unknown type.
JMPS .50:
.B: MOV CX,pfcoffSYM_DTYPE_NULL <<8 + pfcoffSYM_TYPE_BYTE ; >> 0x000C
JMPS .50:
.U:
.W: MOV CX,pfcoffSYM_DTYPE_NULL <<8 + pfcoffSYM_TYPE_WORD ; >> 0x000D
JMPS .50:
.D: MOV CX,pfcoffSYM_DTYPE_NULL <<8 + pfcoffSYM_TYPE_DWORD ; >> 0x000F
JMPS .50:
.Q: MOV CX,pfcoffSYM_DTYPE_NULL <<8 + pfcoffSYM_TYPE_UINT ; >> 0x000E
JMPS .50:
.T: MOV CX,pfcoffSYM_DTYPE_NULL <<8 + pfcoffSYM_TYPE_LONGDOUBLE ; >> 0x0010
JMPS .50:
.A: MOV CX,pfcoffSYM_DTYPE_POINTER <<8 + pfcoffSYM_TYPE_VOID ; >> 0x0101
.50:MOV [EBX+PFCOFF_SYMBOL.Type],CX
.90:EndProcedure PfcoffSymSymbol
PfcoffStub..PfcoffStubEnd represent compiled
16bit SMALL MZ program, built in euroasm.exefile. It reports a message This program was launched in DOS but it requires Windows.
coffstub.exewas created from the source coffstub.htm , it is used as the default stub when the program option STUBFILE= is empty or when it specifies nonexisting or damaged file.
[.data] PfcoffStub:: INCLUDEBIN "../objlib/coffstub.exe" PfcoffStubEnd:: [.text]
.Machine, .TimeDateStamp, .SizeOfOptionalHeader, .Characteristics
. Other members are zeroed.
PfcoffFileHeader Procedure FileHeader,PgmPtr
MOV EDI,[%FileHeader]
MOV EBX,[%PgmPtr]
Clear EDI,Size=SIZE#PFCOFF_FILE_HEADER
MOV EAX,[EBX+PGM.Pgmopt.Status]
JSt EAX,pgmoptWidthMask,.40:
; Program width is not specified.
ListGetFirst [EBX+PGM.SssList]
JZ .40:
.20:JNSt [EAX+SSS.Status],sssSegment,.30:
JNSt [EAX+SSS.Purpose],sssPurposeRegular,.30:
MOV EAX,[EAX+SSS.Status]
AND EAX,sssWidthMask ; Identical with pgmoptWidthMask.
JMPS .40:
.30:ListGetNext EAX
JNZ .20:
.40: ; Assume 64bit.
MOV ECX,pfcoffFILE_MACHINE_AMD64 ; PFCOFF_FILE_HEADER.Machine.
MOV ESI,SIZE# PFPE_OPTIONAL_HEADER64 ; PFCOFF_FILE_HEADER.SizeOfOptionalHeader.
MOV EDX,pfcoffFILE_LARGE_ADDRESS_AWARE ; PFCOFF_FILE_HEADER.Characteristics.
JSt EAX,pgmoptWidth64,.70: ; Otherwise assume 32bit.
MOV ECX,pfcoffFILE_MACHINE_I386 ; PFCOFF_FILE_HEADER.Machine.
MOV ESI,SIZE# PFPE_OPTIONAL_HEADER32 ; PFCOFF_FILE_HEADER.SizeOfOptionalHeader.
XOR EDX,EDX ; PFCOFF_FILE_HEADER.Characteristics.
JSt EAX,pgmoptWidth16,.70:
MOV EDX,pfcoffFILE_32BIT_MACHINE
.70:MOV [EDI+PFCOFF_FILE_HEADER.Machine],CX
Dispatch AL,pgmoptPE,pgmoptDLL
JMPS .80: ; SizeOfOptionalHeader in nonexecutables is left at 0.
.pgmoptDLL: OR EDX,pfcoffFILE_EXECUTABLE_IMAGE + pfcoffFILE_DLL
.pgmoptPE: OR EDX,pfcoffFILE_EXECUTABLE_IMAGE
MOV [EDI+PFCOFF_FILE_HEADER.SizeOfOptionalHeader],ESI
.80:MOV [EDI+PFCOFF_FILE_HEADER.Characteristics],DX
MOV ECX,[Ea.Eaopt.TimeStamp::]
MOV [EDI+PFCOFF_FILE_HEADER.TimeDateStamp],ECX
EndProcedure PfcoffFileHeader
.NumberOfSections will be incremented.
This incremented section ordinal will be also written to SSS.SegmIndex of the Segment.
PfcoffSegmCreate Procedure Segment, Program, SectionHeaderBuffer, FileHeader
MOV EBX,[%FileHeader]
MOV ESI,[%Segment]
MOVZXW EDX,[EBX+PFCOFF_FILE_HEADER.NumberOfSections]
INC EDX ; One-based section number.
MOV [ESI+SSS.SegmIndex],EDX
TEST EDX,0xFFFF_0000
Msg '7913',cc=NZ ; Number of COFF sections (segments) exceeded 65_535.
MOV [EBX+PFCOFF_FILE_HEADER.NumberOfSections],DX
BufferNew [%SectionHeaderBuffer],SIZE#PFCOFF_SECTION_HEADER
MOV EDI,EAX
SUB EAX,EAX
MOV ECX,SIZE#PFCOFF_SECTION_HEADER / 4
REP STOSD ; Clear the new section header.
EndProcedure PfcoffSegmCreate
PfcoffLoadPgm reads the contents of one COFF object file
and converts it to structures of a fresh new program, which then will be stored on
BasePgm.ModulePgmList.
BasePgm.ModulePgmList as a new
PGM structure.
PfcoffLoadPgm Procedure BasePgm, ObjBegin, ObjSize, FileNamePtr
MOV EDI,[%FileNamePtr]
GetLength$ EDI
MOV EDX,ECX ; EDI,ECX is file name string. Remove path.
LEA ESI,[EDI+ECX-1]
STD
.20:LODSB ; Read the string backward.
CMP AL,'\'
JE .30:
CMP AL,'/'
JE .30:
CMP AL,':'
LOOPNE .20:
.30:CLD
LEA ESI,[EDI+ECX]
SUB EDX,ECX ; ESI,EDX is now file name without path. Remove file extension (usually .obj
).
LEA EDI,[ESI+EDX]
.40:DEC EDI
CMP EDI,ESI
JNA .60:
CMPB [EDI],'.'
JNE .40:
.50:SUB EDI,ESI
JNZ .70:
.60:MOV EDI,EDX ; When the file name has no extension, use it as whole.
.70:; ESI,EDI is now file name without path and without extension, it will be used as the module name.
Invoke EaBufferReserve::,PfcoffLoadPgm
Invoke EaFs2Id::,ESI,EDI,EAX ; Replace nonalphanum with underscores.
BufferRetrieve EAX
Invoke EaBufferRelease::,EAX
Invoke PfcoffLoadModule,[%BasePgm],[%ObjBegin],[%ObjSize],[%FileNamePtr],ESI,ECX,pgmoptCOFF
.90:EndProcedure PfcoffLoadPgm
PfcoffLoadModule reads the contents of one COFF object module
and converts it to structures of a fresh new program, which then will be stored on
BasePgm.ModulePgmList.
The object can be the whole contents of a separate file in COFF format,
or it can be one member of object library in LIBCOF format.
BasePgm.ModulePgmList as a new
PGM structure.
PfcoffLoadModule Procedure BaseProgram, ModBegin, ModSize, FileName$Ptr,ModNamePtr,ModNameSize,Format
ModEnd LocalVar ; Pointer to the end of loaded file.
CoffScnBegin LocalVar ; Pointer to the first section header in memory mapped file.
CoffScnPtr LocalVar ; Pointer to the current section header in memory mapped file.
CoffScnEnd LocalVar ; Pointer behind the last section header in memory mapped file.
CoffScnCount LocalVar ; Number of PFCOFF_SECTION_HEADER records in the file.
CoffScnIndex LocalVar ; Ordinal number of PFCOFF_SECTION_HEADER in COFF file (1,2,3..).
CoffSymPtr LocalVar ; Pointer to the current PFCOFF_SYMBOL record in memory mapped file.
CoffSymCount LocalVar ; Number of PFCOFF_SYMBOL records in the module.
CoffSymIndex LocalVar ; 0-based ordinal number of PFCOFF_SYMBOL in COFF module (0,1,2,3..).
CoffSymAux LocalVar ; Number of auxiliary symbols pending in PFCOFF_SYMBOL table.
CoffStrBegin LocalVar ; Pointer to COFF string table in memory mapped file.
SssAlignment LocalVar ; SSS.Alignment (power of 2).
LinkStm LocalVar Size=SIZE#STM ; Temporary fake statement used in SssCreateSe.
ClearLocalVar
MOV EBX,[%BaseProgram]
MOV EDX,[EBX+PGM.Pool]
MOV EAX,[EBX+PGM.LinePtr]
LEA EDI,[%LinkStm]
MOV [EDI+STM.LinePtr],EAX
; Create loaded module. Simplified intialization inherits Pool from BaseProgram.
ListNew [EBX+PGM.ModulePgmList],Zeroed=yes
JC .90:
MOV EBX,EAX ; EBX is now the new module program.
MOV [EDI+STM.Program],EBX
MOV ESI,[%ModNamePtr]
MOV ECX,[%ModNameSize]
MOV [EBX+PGM.Pool],EDX
PoolStore EDX,ESI,ECX ; Make the PGM.Name nonvolatile.
MOV [EBX+PGM.NamePtr],EAX
MOV [EBX+PGM.NameSize],ECX
ListCreate EDX,SIZE# SSS
MOV [EBX+PGM.SssList],EAX
ListCreate EDX,SIZE# SYM
MOV [EBX+PGM.SymList],EAX
MOV ECX,[%Format]
Invoke PgmoptSetLinkProp::,ECX ; Get default properties for the module format (COFF|LIBCOF).
AND EAX,pgmoptLinkPropMask
CMP ECX,pgmoptLIBCOF
JNE .F0:
SetSt EAX,pgmoptLibMember
.F0:MOV [EBX+PGM.Pgmopt.Status],EAX
MOV ESI,[%ModBegin]
MOV ECX,[%ModSize]
ADD ECX,ESI
MOV [%ModEnd],ECX
; Retrieve information from COFF file header mapped at ESI.
MOVZXW EDX,[ESI+PFCOFF_FILE_HEADER.Machine] ; Try to specify the module width from COFF file header characteristics.
MOVZXW EAX,[ESI+PFCOFF_FILE_HEADER.Characteristics]
MOV ECX,pgmoptCOFF+pgmoptWidth64 ; Assume 64bit COFF.
CMP DX,pfcoffFILE_MACHINE_AMD64
JE .F1:
CMP DX,pfcoffFILE_MACHINE_IA64
JE .F1:
MOV ECX,pgmoptCOFF+pgmoptWidth32 ; Assume 32bit COFF.
JSt EAX,pfcoffFILE_32BIT_MACHINE,.F1:
MOV ECX,pgmoptCOFF+pgmoptWidth16 ; Otherwise assume 16bit COFF.
.F1:SetSt [EBX+PGM.Pgmopt.Status],ECX ; Store format and width of the loaded module. Model is unspecified.
MOV EDX,[ESI+PFCOFF_FILE_HEADER.PointerToSymbolTable] ; File address.
MOV ECX,[ESI+PFCOFF_FILE_HEADER.NumberOfSymbols]
ADD EDX,[%ModBegin] ; Convert FA into pointer to symbol table in mapped memory.
MOV [%CoffSymCount],ECX
MOV [%CoffSymPtr],EDX
MOV EAX,SIZE# PFCOFF_SYMBOL
MUL ECX
ADD EAX,[%CoffSymPtr]
MOV [%CoffStrBegin],EAX ; Pointer to the string table following the symbol table.
MOVZXW EDX,[ESI+PFCOFF_FILE_HEADER.SizeOfOptionalHeader]
MOVZXW ECX,[ESI+PFCOFF_FILE_HEADER.NumberOfSections]
LEA ESI,[ESI + SIZE# PFCOFF_FILE_HEADER + EDX]
MOV [%CoffScnBegin],ESI ; ESI is pointer to the 1st COFF section header.
MOV EAX,SIZE# PFCOFF_SECTION_HEADER
MOV [%CoffScnCount],ECX
SUB ESI,EAX
MOV [%CoffScnPtr],ESI ; Pointer to the current-1 COFF section header in mapped memory.
ADD ESI,EAX
MUL ECX
ADD EAX,ESI
MOV [%CoffScnEnd],EAX
CMP EAX,[%ModEnd]
JNB .E7766: ; Invalid format of COFF object file "!1S".
.G1:; Convert section headers to program segments in the loop .G1: .. .G9:.
MOV ESI,[%CoffScnPtr]
ADD ESI,SIZE# PFCOFF_SECTION_HEADER
MOV [%CoffScnPtr],ESI ; ESI=^PFCOFF_SECTION_HEADER, EBX=^PGM of the loaded module.
INCD [%CoffScnIndex]
CMP ESI,[%CoffScnEnd]
JNB .H1: ; If there are no more section headers left to convert.
MOV EDX,[ESI+PFCOFF_SECTION_HEADER.Characteristics]
; Find segment alignment.
MOV EAX,1
MOV ECX,pfcoffSCN_ALIGN_MASK
AND ECX,EDX
SHR ECX,20
JZ .G2:
DEC ECX
SHL EAX,CL ; Convert pfcoffSCN alignment to SSS.Alignment.
.G2:MOV [%SssAlignment],EAX
; Find segment properties (SSS.Status).
MOV EDI,pgmoptWidthMask ; Width of the loaded segment is specified by module width.
AND EDI,[EBX+PGM.Pgmopt.Status] ; Encoding of pgmoptWidthMask is synchronized with sssWidthMask.
OR EDI,sssSegment+sssPublic ; "Section" in MS terminology is "Segment" in €ASM.
; Find segment purpose from section characteristics in EDX.
XOR EAX,EAX
JNSt EDX,pfcoffSCN_CNT_CODE,.GC:
JNSt EDX,pfcoffSCN_MEM_EXECUTE,.GC:
OR EAX,sssPurposeCODE
.GC:JNSt EDX,pfcoffSCN_MEM_READ,.GS:
JNSt EDX,pfcoffSCN_CNT_INITIALIZED_DATA,.GR:
JNSt EDX,pfcoffSCN_MEM_WRITE,.GD:
OR EAX,sssPurposeDATA
.GD:JSt EDX,pfcoffSCN_MEM_WRITE,.GR:
OR EAX,sssPurposeRODATA
.GR:JNSt EDX,pfcoffSCN_CNT_UNINITIALIZED_DATA,.GS:
JNSt EDX,pfcoffSCN_MEM_WRITE,.GS:
OR EAX,sssPurposeBSS
.GS:XCHG EAX,EDX ; EDX=SSS.Purpose.
; Find segment name.
LEA ESI,[ESI+PFCOFF_SECTION_HEADER.Name]
MOV ECX,8 ; At first assume short section name.
CMPB [ESI],'/' ; Longnames are represented as "/123" (123 is offset in the string table).
JNE .G7: ; If segment name is short, it was stored in section header directly.
INC ESI ; Otherwise skip the slash.
LodD ESI,Size=7 ; Load decimal offset in the string table into EAX.
.G6:MOV ESI,[%CoffStrBegin] ; String table in mapped memory. At least 4 bytes long.
CMP EAX,4
JNA .E7766: ; Invalid format of COFF object file "!1S".
CMP EAX,[ESI] ; Dword at ESI is the size of string table.
JNB .E7766: ; Invalid format of COFF object file "!1S".
ADD ESI,EAX
GetLength$ ESI ; Segment name at ESI is a zero-terminated string. Get its length to ECX.
.G7:StripSpaces ESI,ECX ; Get rid of trailing NULL characters, if any.
; Create new segment in the loaded module. ESI,ECX=name, EDX=purpose, EDI=status.
LEA EAX,[%LinkStm] ; ^STM.
Invoke SssCreateSe::,EAX,0,ESI,ECX,EDI,EDX,[%SssAlignment]
JC .G9: ; Errors were already reported by SssCreateSe.
MOV EDI,EAX ; EDI=^SSS.
MOV ECX,[%CoffScnIndex]
MOV [EDI+SSS.SegmIndex],ECX ; Set 1-based ordinal in COFF section headers.
MOV [EDI+SSS.Purpose],EDX
Invoke SssGuessPurpose::,EDI ; If the purpose EDX wasn't specified by characteristics, guess by name.
MOV ESI,[%CoffScnPtr] ; Restore ESI. Examine if the section has initialized raw data.
MOV EAX,[ESI+PFCOFF_SECTION_HEADER.SizeOfRawData] ; Nonzero in BSS.
MOV ECX,[ESI+PFCOFF_SECTION_HEADER.PointerToRawData] ; Zero in BSS.
MOV [EDI+SSS.TopLow],EAX
JECXZ .G9: ; Skip if uninitialized data section.
SetSt [EDI+SSS.Status],sssNotBSS
ADD ECX,[%ModBegin] ; Convert FA to pointer.
CMP ECX,[%ModEnd]
JNB .E7766: ; Invalid format of COFF object file "!1S".
BufferStore [EDI+SSS.EmitBuffer],ECX,EAX ; Segment raw data.
.G9:JMP .G1 ; Section header ESI is converted, go and get the next one.
.E7766:Msg '7765',EBX ; Invalid format of COFF object module "!1S".
JMP .90:
.H1:; Convert symbols from COFF symbol table to PGM EBX symbols in the loop .H2: .. .M9:.
XOR EAX,EAX
MOV [%CoffSymAux],EAX
DEC EAX
MOV [%CoffSymIndex],EAX
SUBD [%CoffSymPtr],SIZE# PFCOFF_SYMBOL ; Symbol table pass is initialized.
.H2:MOV ESI,[%CoffSymPtr]
MOV EAX,[%CoffSymIndex]
ADD ESI,SIZE# PFCOFF_SYMBOL
INC EAX
MOV [%CoffSymPtr],ESI
MOV [%CoffSymIndex],EAX
CMP EAX,[%CoffSymCount]
JAE .Q1: ; When there are no more symbols records left to convert.
MOV ECX,[%CoffSymAux] ; Number of pending Aux records.
JECXZ .H3:
DEC ECX ; PFCOFF_SYMBOL ESI has auxilliary records.
MOV [%CoffSymAux],ECX
JMP .H2: ; Ignore aux record(s).
.H3:; Symbol name.
LEA EDX,[ESI+PFCOFF_SYMBOL.Name]
MOV ECX,[EDX] ; If the symbol name is long, LSD=0.
JECXZ .H4:
MOV ECX,8 ; Symbol name EDX,ECX is short, NULL padded.
JMP .H5:
.H4:MOV EAX,[EDX+4] ; Get the offset of long symbol name in string table.
MOV EDX,[%CoffStrBegin] ; EDX=^string table.
CMP EAX,[EDX] ; The first dword is the table size.
JNB .E7766: ; Return error if out of string table.
ADD EDX,EAX ; EDX is now pointer to ASCIIZ string.
GetLength$ EDX
.H5:StripSpaces,EDX,ECX ; Get rid of trailing NULL characters, if any.
MOVZXB EAX,[ESI+PFCOFF_SYMBOL.NumberOfAuxSymbols] ; ESI=^PFCOFF_SYMBOL, EDX,ECX=name, EBX=^PGM.
MOV [%CoffSymAux],EAX ; Number of pending Aux records which follow symbol ESI.
TEST EAX
JZ .M1: ; If it has no auxilliary record, it can't be a section's symbol.
CMPB [ESI+PFCOFF_SYMBOL.StorageClass],pfcoffSYM_CLASS_FILE
JE .H2: ; Ignore COFF symbol of type '.file',
MOVSXW EAX,[ESI+PFCOFF_SYMBOL.SectionNumber] ; Update COFF symbol which represents a COFF section as symSe. It has 1 aux record.
TEST EAX
JLE .M1: ; If not positive, it can't be a segment's symbol symSe.
CMPB [ESI+PFCOFF_SYMBOL.StorageClass],pfcoffSYM_CLASS_STATIC
JNE .M1: ; If storage class != 3, it can't be a segment's symbol.
Invoke SssFindByIndex::,EAX,EBX ; COFF symbol at ESI represents a COFF section with SectionNumber EAX.
JNC .H7:
.E7941:Msg '7941',EDX,EDI,EBX ; Symbol name "!1$" mismatched COFF section "!2S" in module "!3S".
JMP .H2: ; If the segment was not declared in COFF section header.
.H7:MOV EDI,[EAX+SSS.SymPtr]
TEST EDI
JZ .E7766:
Compare [EDI+SYM.NamePtr],[EDI+SYM.NameSize],EDX,ECX
JNE .E7941: ; Symbol name "!1$" mismatched COFF section "!2S" in module "!3S".
MOV EAX,[%CoffSymIndex] ; Update symSe EDI which was already created in module EBX by SssCreateSe at .G7.
MOV [EDI+SYM.NameIndex],EAX
JMP .H2: ; Go get the next COFF symbol.
.E7944:Msg '7944',ECX,EDI,EBX ; COFF section #!1D of symbol "!2S" in module "!3S" was not found.
JMP .M9:
.M1: ; COFF symbol at ESI is standard, global or scalar. Its name is EDX,ECX.
ListNew [EBX+PGM.SymList],Zeroed=yes ; Create a new symbol in the loaded module.
MOV EDI,EAX
PoolStore [EBX+PGM.Pool],EDX,ECX
MOV [EDI+SYM.NamePtr],EAX
MOV [EDI+SYM.NameSize],ECX
MOV EAX,[%CoffSymIndex]
MOV EDX,[EBX+PGM.LinePtr]
MOV [EDI+SYM.NameIndex],EAX
MOV [EDI+SYM.LinePtr],EDX
MOV EAX,[ESI+PFCOFF_SYMBOL.Value]
MOV [EDI+SYM.OffsetLow],EAX
; Get scope and section assigned to COFF symbol ESI.
MOVSXW ECX,[ESI+PFCOFF_SYMBOL.SectionNumber] ; -2,-1,0,1,2,3,,,
TEST ECX
JZ .M3: ; pfcoffSYM_UNDEFINED is external.
JS .M5: ; pfcoffSYM_ABSOLUTE|pfcoffSYM_DEBUG is treated as scalar (SYM.Section=0).
Invoke SssFindByIndex::,ECX,EBX ; Segment with SSS.SegmIndex=ECX should have been already loaded.
JC .E7944: ; COFF section #!1D of symbol "!2S" in module "!3S" was not found.
MOV [EDI+SYM.Section],EAX ; Symbol EDI is defined in segment EAX of program EBX.
MOVZXB EDX,[ESI+PFCOFF_SYMBOL.StorageClass] ; Symbol is private of public.
Dispatch DL,pfcoffSYM_CLASS_STATIC,pfcoffSYM_CLASS_EXTERNAL
Msg '2733',EDX,EDI,EBX ; Unsupported StorageClass !1D of symbol "!2S" in COFF module !3S. Ignored.
JMP .H2:
.pfcoffSYM_CLASS_EXTERNAL: ; Symbol is public.
SetSt [EDI+SYM.Status],symPublic
.pfcoffSYM_CLASS_STATIC: ; Symbol is private (nonglobal).
JMP .M5:
.M3:SetSt [EDI+SYM.Status],symExtern ; Symbol is external.
Invoke SssCreateExtern::,EDI,EBX ; Assign SYM.Section with extern pseudosegment.
.M5:; Convert COFF symbol type to SYM.Status in EAX.
MOV EAX,[EDI+SYM.Status]
SetSt EAX,symUsed
MOVZXW EDX,[ESI+PFCOFF_SYMBOL.Type]
MOV AL,'A'
CMP DH,pfcoffSYM_DTYPE_FUNCTION
JNE .M7:
SetSt EAX,symProc
.M7:Dispatch DL,pfcoffSYM_TYPE_CHAR,pfcoffSYM_TYPE_SHORT,pfcoffSYM_TYPE_INT,\
pfcoffSYM_TYPE_LONG,pfcoffSYM_TYPE_FLOAT,pfcoffSYM_TYPE_DOUBLE, \
pfcoffSYM_TYPE_BYTE,pfcoffSYM_TYPE_WORD,pfcoffSYM_TYPE_UINT, \
pfcoffSYM_TYPE_DWORD,pfcoffSYM_TYPE_LONGDOUBLE
JMP .M9: ; SYM_TYPE_VOID.
.pfcoffSYM_TYPE_INT:
.pfcoffSYM_TYPE_UINT: ; DWORD or QWORD, depending on program width.
MOV AL,'D'
JNSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.M9:
MOV AL,'Q'
JMP .M9:
.pfcoffSYM_TYPE_BYTE:
.pfcoffSYM_TYPE_CHAR:
MOV AL,'B'
JMP .M9:
.pfcoffSYM_TYPE_WORD:
.pfcoffSYM_TYPE_SHORT:
MOV AL,'W'
JMP .M9:
.pfcoffSYM_TYPE_DWORD:
.pfcoffSYM_TYPE_LONG:
.pfcoffSYM_TYPE_FLOAT:
MOV AL,'D'
JMP .M9:
.pfcoffSYM_TYPE_DOUBLE:
MOV AL,'Q'
JMP .M9:
.pfcoffSYM_TYPE_LONGDOUBLE
MOV AL,'T'
.M9:MOV [EDI+SYM.Status],EAX
JMP .H2: ; COFF symbol ESI is converted, go get the next one.
.Q1:Invoke PfDrectveDestroy::,EBX ; Transform COFF section [.drectve] (if exists) to symbols in module EBX.
.R1: ; Convert COFF relocations to program relocations for each program segment in the loop .R2: .. .90:.
MOV ESI,[%CoffScnBegin]
XOR EAX,EAX
SUB ESI,SIZE# PFCOFF_SECTION_HEADER
MOV [%CoffScnIndex],EAX
MOV [%CoffScnPtr],ESI
.R2:MOV ESI,[%CoffScnPtr]
ADD ESI,SIZE# PFCOFF_SECTION_HEADER
MOV [%CoffScnPtr],ESI
INCD [%CoffScnIndex]
CMP ESI,[%CoffScnEnd]
JNB .90:
MOVZXW ECX,[ESI+PFCOFF_SECTION_HEADER.NumberOfRelocations]
JECXZ .R2: ; The next COFF section.
Invoke SssFindByIndex::,[%CoffScnIndex],EBX
JNC .R4:
.E7943:Msg '7943',[%CoffScnIndex],EBX ; COFF section #!1D in module "!2S" was not found.
JMP .R2:
.R4:MOV EDX,[ESI+PFCOFF_SECTION_HEADER.PointerToRelocations]
MOV ESI,EAX
ADD EDX,[%ModBegin] ; EDX=^PFCOFF_RELOCATION, ESI=^SSS, EBX=^PGM
.R5:Invoke PfcoffRelocation2Reloc,EDX,ESI,EBX
ADD EDX,SIZE# PFCOFF_RELOCATION
LOOP .R5: ; The next relocation.
JMP .R2: ; The next COFF section.
.90:EndProcedure PfcoffLoadModule
PfcoffRelocation2Reloc Procedure CoffRelocation, SssSegment, ModProgram
Reloc LocalVar Size=SIZE# RELOC ; Working room for the program relocation.
MOV EDX,[%CoffRelocation]
MOV ESI,[%SssSegment]
MOV EBX,[%ModProgram]
BufferNew [ESI+SSS.RelocBuffer],SIZE# RELOC, Zeroed=Yes
MOV EDI,EAX
MOV EAX,[EDX+PFCOFF_RELOCATION.VirtualAddress]
MOV [EDI+RELOC.Section],ESI
MOV [EDI+RELOC.OrgLow],EAX
MOV ECX,[EDX+PFCOFF_RELOCATION.SymbolTableIndex]
Invoke SymFindByIndex::,ECX,EBX
JC .E7736: ; Symbol #!1D in COFF section [!2S] was not found.',0
MOV [EDI+RELOC.Symbol],EAX
MOVZXW EAX,[EDX+PFCOFF_RELOCATION.Type]
XOR ECX,ECX
JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.AMD64:
.I386: ; Machine=I386 in 16|32bit programs.
Dispatch AX,0x0006,0x0014,0x0007,0x0001,0x0002 ; Supported types of I386 relocations.
.E7735:Msg '7734',EAX,ESI,[EDI+RELOC.OrgLow] ; Relocation type 0x!1W at [!2S]:!3H is not resolvable in this program format.
JMP .90:
.E7736:Msg '7736',ECX,ESI ; Symbol #!1D in COFF section [!2S] was not found.
JMP .90:
.0x0001:MOV EAX,relocWidth16+relocAbsVA ; IMAGE_REL_I386_DIR16.
JMP .30:
.0x0002:MOV EAX,relocWidth16+relocRel ; IMAGE_REL_I386_REL16.
JMP .30:
.0x0006:MOV EAX,relocWidth32+relocAbsVA ; IMAGE_REL_I386_DIR32.
JMP .30:
.0x0007:MOV EAX,relocWidth32+relocAbsRVA ; IMAGE_REL_I386_DIR325NB.
JMP .30:
.0x0014:MOV EAX,relocWidth32+relocRel ; IMAGE_REL_I386_REL32.
JMP .30:
.AMD64:; Machine=AMD64 in 64bit programs.
Dispatch AX,0004h,0001h,0002h,0003h,0008h,0005h,0006h,0007h,0009h ; Supported types of AMD64 relocations.
JMP .E7735: ; Relocation type 0x!1W at [!2S]:!3H is not resolvable in this program format.
.0005h:MOV EAX,relocWidth32+relocRel ; IMAGE_REL_AMD64_REL32_1.
ADD ECX,1
JMP .30:
.0006h:MOV EAX,relocWidth32+relocRel ; IMAGE_REL_AMD64_REL32_2.
ADD ECX,2
JMP .30:
.0007h:MOV EAX,relocWidth32+relocRel ; IMAGE_REL_AMD64_REL32_3.
ADD ECX,3
JMP .30:
.0008h:MOV EAX,relocWidth32+relocRel ; IMAGE_REL_AMD64_REL32_4.
ADD ECX,4
JMP .30:
.0009h:MOV EAX,relocWidth32+relocRel ; IMAGE_REL_AMD64_REL32_5.
ADD ECX,5
JMP .30:
.0001h:MOV EAX,relocWidth64+relocAbsVA ; IMAGE_REL_AMD64_ADDR64.
JMP .30:
.0002h:MOV EAX,relocWidth32+relocAbsVA ; IMAGE_REL_AMD64_ADDR32.
JMP .30:
.0003h:MOV EAX,relocWidth32+relocAbsRVA ; IMAGE_REL_AMD64_ADDR32NB.
JMP .30:
.0004h:MOV EAX,relocWidth32+relocRel ; IMAGE_REL_AMD64_REL32.
;JMP .30:
.30:OR [EDI+RELOC.Status],EAX
JNSt EAX,relocRel,.80:
AND EAX,relocWidthMask
SHR EAX,19 ; Convert relocWidthMask to the object size 2|4|8.
ADD ECX,EAX
.80:MOV EAX,ECX
CDQ
SUB [EDI+RELOC.AddendLow],EAX
SBB [EDI+RELOC.AddendHigh],EDX
.90:EndProcedure PfcoffRelocation2Reloc
PfcoffSymTable Procedure Program, SymTableBuffer, StringTableBuffer
MOV EBX,[%SymTableBuffer]
BufferClear EBX
Invoke PfcoffSymFile,Ea.SrcFile::,EBX ; Create '.file' COFF symbol in the buffer EBX.
MOV EDX,[%Program]
BufferRetrieve [EDX+PGM.SymOrdBuffer]
SHR ECX,2 ; Number of SYM symbols in the %Program.
JZ .90:
MOV EDX,[%StringTableBuffer]
.10:LODSD ; EAX=^SYM.
JNSt [EAX+SYM.Status],symSe,.20:
MOV EDI,[EAX+SYM.Section]
JNSt [EDI+SSS.Status],sssSegment|sssGroup,.20:
Invoke PfcoffSymSegment,EAX,EBX,EDX ; Create CLASS_STATIC (section type) pair of COFF symbols.
JMP .80:
.20:Invoke PfcoffSymSymbol,EAX,EBX,EDX ; Create scalar or local or global COFF symbol.
.80:DEC ECX
JNZ .10: ; The next symbol.
.90:EndProcedure PfcoffSymTable
PfcoffCompile Procedure OutputStream, Pgm
CoffFileHeader LocalVar Size=SIZE#PFCOFF_FILE_HEADER ; Room for PFCOFF_FILE_HEADER object.
SectionHeaderBuf LocalVar ; Pointer to BUFFER which keeps PFCOFF_SECTION_HEADER objects, one for each segment.
SymbolTableBuf LocalVar ; Pointer to BUFFER for PFCOFF_SYMBOL records.
StringTableBuf LocalVar ; Pointer to BUFFER for longname strings.
Machine LocalVar ; LSW specifies PFCOFF_FILE_HEADER.Machine.
; Initialize temporary data structures.
Invoke EaBufferReserve::,PfcoffCompile
MOV [%SectionHeaderBuf],EAX ; Section headers buffer.
Invoke EaBufferReserve::,PfcoffCompile
MOV [%SymbolTableBuf],EAX ; Symbols buffer.
Invoke EaBufferReserve::,PfcoffCompile
MOV [%StringTableBuf],EAX ; String table buffer.
MOV EDX,EAX
BufferStoreDword EDX,4 ; Initialize dword StringTableSize in the buffer EDX.
MOV EBX,[%Pgm]
MOV EAX,pgmoptFormatMask
AND EAX,[EBX+PGM.Pgmopt.Status]
CMP AL,pgmoptCOFF
JNE .10: ; Do not create [.directve] segment in LIBCOF format.
Invoke PfDrectveCreate::,EBX
.10: Invoke PgmOrderSegments::,EBX
Invoke PgmOrderSymbols::,EBX
LEA EDI,[%CoffFileHeader]
Invoke PfcoffFileHeader,EDI,EBX ; Create COFF file header. Optional header is not used in this format.
MOVZXW EAX,[EDI+PFCOFF_FILE_HEADER.Machine]
MOV [%Machine],EAX
MOV ESI,[%SectionHeaderBuf]
Invoke PfcoffSectHeaders,EBX,ESI,EDX ; Create COFF section headers.
BufferRetrieve ESI
MOV EAX,ECX
SUB EDX,EDX
MOV ECX,SIZE# PFCOFF_SECTION_HEADER
DIV ECX
MOV [EDI+PFCOFF_FILE_HEADER.NumberOfSections],AX
MOV ESI,[%SymbolTableBuf]
Invoke PfcoffSymTable,EBX,ESI,[%StringTableBuf] ; Create symbol table.
BufferRetrieve ESI
MOV EAX,ECX
SUB EDX,EDX
MOV ECX,SIZE# PFCOFF_SYMBOL
DIV ECX
MOV [EDI+PFCOFF_FILE_HEADER.NumberOfSymbols],EAX
CALL .Stream: ; Update COFF components in the 1st dummy pass.
StreamClear [%OutputStream]
CALL .Stream: ; This time store updated COFF components to the %OutputStream.
Invoke PgmResizeGroups::,EBX
Invoke EaBufferRelease::,[%SymbolTableBuf]
Invoke EaBufferRelease::,[%StringTableBuf]
Invoke EaBufferRelease::,[%SectionHeaderBuf]
EndProcedure PfcoffCompile
PfcoffCompile.Stream: PROC1 ; EBX=^PGM (not clobbered).
MOV EDX,[%OutputStream]
; COFF file header.
LEA EDI,[%CoffFileHeader]
StreamStore EDX,EDI,SIZE# PFCOFF_FILE_HEADER
; COFF section headers.
BufferRetrieve [%SectionHeaderBuf]
StreamStore EDX,ESI,ECX
MOV EDI,ESI ; EDI=pointer to the 1st COFF section header.
BufferRetrieve [EBX+PGM.SegOrdBuffer]
SHR ECX,2
JZ .S8:
.S2: LODSD
PUSH ECX,ESI
MOV ESI,EAX ; ESI=^SSS, EDI=^PFCOFF_SECTION_HEADER.
JNSt [ESI+SSS.Status],sssSegment,.S7:
MOV EAX,[ESI+SSS.TopLow]
MOV EDX,[ESI+SSS.TopHigh]
SUB EAX,[ESI+SSS.BottomLow]
SBB EDX,[ESI+SSS.BottomHigh]
Msg cc=NZ,'8525',ESI ; Size of segment [!1S] exceeded 4 GB.
MOV [EDI+PFCOFF_SECTION_HEADER.SizeOfRawData],EAX
MOV EDX,[%OutputStream]
JNSt [ESI+SSS.Status],sssNotBSS, .S4:
Invoke EaStreamAlign::, EDX,[EBX+PGM.Pgmopt.FileAlign],0 ; Default FileAlign is 4 in COFF format.
StreamGetSize EDX ; EAX=aligned file-address of the emitted raw data.
MOV [EDI+PFCOFF_SECTION_HEADER.PointerToRawData],EAX
MOV [ESI+SSS.BottomFA],EAX
PUSH ESI
BufferRetrieve [ESI+SSS.EmitBuffer]
StreamStore EDX,ESI,ECX
POP ESI
MOV [EDI+PFCOFF_SECTION_HEADER.SizeOfRawData],ECX
ADD ECX,[ESI+SSS.BottomFA]
MOV [ESI+SSS.TopFA],ECX
BufferRetrieve [ESI+SSS.RelocBuffer]; ESI now points to an array of RELOC records.
JECXZ .S4: ; Skip if no relocations.
Invoke EaStreamAlign::, EDX,2,0 ; COFF relocations are WORD aligned.
StreamGetSize EDX ; EAX=aligned file-address of the COFF relocations.
MOV [EDI+PFCOFF_SECTION_HEADER.PointerToRelocations],EAX
ADD ECX,ESI ; ECX=^top of the array of RELOC records.
SUB EAX,EAX ; EAX=counter of relocations.
.S3: Invoke PfcoffStreamReloc,EDX,ESI,[%Machine] ; Convert and stream the RELOC at ESI.
INC EAX ; EAX=counter of relocations.
ADD ESI,SIZE# RELOC
CMP ESI,ECX
JB .S3:
MOV [EDI+PFCOFF_SECTION_HEADER.NumberOfRelocations],EAX
.S4: ADD EDI,SIZE# PFCOFF_SECTION_HEADER
.S7: POP ESI,ECX
DEC ECX
JNZ .S2: ; The next SSS segment.
.S8: ; COFF symbol table.
Invoke EaStreamAlign::, EDX,2,0 ; COFF symbols are WORD aligned.
StreamGetSize EDX ; EAX=aligned file-address of the COFF symbol table.
LEA EDI,[%CoffFileHeader]
MOV [EDI+PFCOFF_FILE_HEADER.PointerToSymbolTable],EAX
BufferRetrieve [%SymbolTableBuf]
StreamStore EDX,ESI,ECX
; COFF string table.
BufferRetrieve [%StringTableBuf]
MOV [ESI],ECX ; Update StringTable size.
StreamStore EDX,ESI,ECX
RET
ENDP1 PfcoffCompile.Stream:
%Program.SegOrdBuffer and updates their members
SSS.NameIndex, PFCOFF_SECTION_HEADER.Name, PFCOFF_SECTION_HEADER.Characteristics..
PfcoffSectHeaders Procedure Program, SectHeadersBuffer, StringTableBuffer
SegmIndex LocalVar
MOV EBX,[%SectHeadersBuffer]
BufferClear EBX
SUB EAX,EAX
MOV [%SegmIndex],EAX
MOV EDX,[%Program]
BufferRetrieve [EDX+PGM.SegOrdBuffer]
SHR ECX,2 ; Number of segments in program EDX.
JZ .90:
.10:LODSD ; EAX=^SSS.
PUSH ECX,ESI
JNSt [EAX+SSS.Status],sssSegment,.80:
MOV ECX,[%SegmIndex]
INC ECX
MOV [%SegmIndex],ECX
MOV [EAX+SSS.SegmIndex],ECX
MOV ESI,EAX ; ESI=^SSS.
BufferNew EBX,SIZE# PFCOFF_SECTION_HEADER, Zeroed=Yes
MOV EDX,EAX ; EDX=^PFCOFF_SECTION_HEADER.
MOV EAX,ESI ; EAX=^SSS.
; PFCOFF_SECTION_HEADER.Name.
MOV ECX,[EAX+SSS.NameSize]
MOV ESI,[EAX+SSS.NamePtr]
LEA EDI,[EDX+PFCOFF_SECTION_HEADER.Name]
CMP ECX,8
JBE .30:
.20: PUSHAD ; EAX=^SSS, EBX=%SectHeaderBuffer, ESI,ECX=SSS.Name, EDX=PFCOFF_SECTION_HEADER, EDI=PFCOFF_SECTION_HEADER.Name
MOV EBX,[%StringTableBuffer]
TEST EBX
JNZ .25: ; Skip if long section names are supported via string table.
Msg '3541',EAX ; Segment name "!1S" is too long, truncated in output file.
MOV ECX,8 ; Executable formats limit segment name size to 8 characters.
REP MOVSB
JMP .29:
.25: PUSH ECX,ESI
BufferRetrieve EBX
MOV EDX,ECX ; Remember buffer offset of the free space in StringTableBuffer.
POP ESI,ECX
BufferStore EBX,ESI,ECX ; Store long name into the string table.
BufferStoreByte EBX,0 ; Terminating zero.
MOV AL,'/'
STOSB ; Instead of long segment name store /ASCII_offset to section header.Name.
MOV EAX,EDX ; Offset within string table.
StoD EDI,Size=7
.29: POPAD
JMP .40:
.30: REP MOVSB
.40: MOV EDI,EAX
; PFCOFF_SECTION_HEADER.Characteristics. EDI=^SSS, EDX=^PFCOFF_SECTION_HEADER.
Invoke SssGetCoffCharacteristics::,EDI
MOV [EDX+PFCOFF_SECTION_HEADER.Characteristics],EAX
.80:POP ESI,ECX
DEC ECX
JNZ .10: ; The next segment.
.90:EndProcedure PfcoffSectHeaders
PfcoffStreamReloc Procedure Stream, Reloc, Machine
EmittedBottom LocalVar ; Pointer to the bottom of emitted data in SSS.EmitBuffer.
EmittedTop LocalVar ; Pointer to the top of emitted data in SSS.EmitBuffer.
CoffRelocation LocalVar Size=SIZE# PFCOFF_RELOCATION
MOV ESI,[%Reloc]
JSt [ESI+RELOC.Status],relocIgnore,.90:
LEA EDI,[%CoffRelocation]
MOV EAX,[ESI+RELOC.OrgLow]
MOV [EDI+PFCOFF_RELOCATION.VirtualAddress],EAX ; Offset of the relocated DWORD|QWORD memory unit.
MOV ECX,[ESI+RELOC.Symbol]
JECXZ .10:
MOV ECX,[ECX+SYM.NameIndex] ; Target symbol identification.
.10: MOV [EDI+PFCOFF_RELOCATION.SymbolTableIndex],ECX
; Get rid of RELOC.Addend: add it to the relocated memory unit in emitted code|data, and then clear the RELOC.Addend.
MOV ESI,[ESI+RELOC.Section]
BufferRetrieve [ESI+SSS.EmitBuffer]
ADD ECX,ESI
MOV [%EmittedBottom],ESI
MOV [%EmittedTop],ECX
MOV ESI,[%Reloc]
MOV ECX,[ESI+RELOC.Status]
MOV EBX,relocWidthMask
AND EBX,ECX
SHR EBX,19 ; Compute size of relocate memory unit (2|4|8).
MOV EAX,[ESI+RELOC.AddendLow]
MOV EDX,[ESI+RELOC.AddendHigh]
JNSt ECX,relocRel,.20:
ADD EAX,EBX ; COFF_RELOCATION correction.
ADC EDX,0
.20: MOV ESI,[ESI+RELOC.OrgLow]
ADD ESI,[%EmittedBottom]
CMP ESI,[%EmittedTop]
JNB .E6762:
MOV EBX,ECX
AND ECX,relocWidthMask
Dispatch ECX,relocWidth32,relocWidth64,relocWidth16
MOV ESI,[%Reloc]
Msg '7729',[ESI+RELOC.Section],[ESI+RELOC.OrgLow] ; Unspecified relocation width at [!2S]:!3Hh.
JMP .90:
.E7731:MOV ESI,[%Reloc]
Msg '7731',EDX,[ESI+RELOC.Section],[ESI+RELOC.OrgLow] ; Invalid reloc type 0x!1H at [!2S]:!3Hh.
JMP .90:
.E6762:MOV ESI,[%Reloc]
Msg '6762',[ESI+RELOC.Section],[ESI+RELOC.OrgLow] ; Relocation [!1S]:!2H out of range.
JMP .90:
.relocWidth64:
ADD [ESI+0],EAX
ADC [ESI+4],EDX
JMP.30:
.relocWidth16:
ADD [ESI],AX
JMP .30:
.relocWidth32:
ADD [ESI],EAX
.30: XOR EAX,EAX
MOV ESI,[%Reloc]
MOV [ESI+RELOC.AddendLow],EAX
MOV [ESI+RELOC.AddendHigh],EAX
; Convert RELOC.Status EBX to PFCOFF_RELOCATION.Type.
JSt EBX,relocWidth32,.Width32:
JSt EBX,relocWidth64,.Width64:
JSt EBX,relocWidth16,.Width16:
.Width16:
MOV AL,1 ; 1: IMAGE_DIR_I386_DIR16.
JSt EBX,relocAbsVA,.70:
INC EAX ; 2: IMAGE_REL_I386_REL16.
JSt EBX,relocRel,.70:
MOV AL,9 ; 9: IMAGE_REL_I386_SEG12.
JSt EBX,relocPara,.70:
JMP .E7731:
.Width64:
MOV AL,1 ; 1: IMAGE_REL_AMD64_ADDR64.
CMPW [%Machine],pfcoffFILE_MACHINE_AMD64
JNE .E7731:
JSt EBX,relocAbsVA,.70:
JMP .E7731:
.Width32:
CMPW [%Machine],pfcoffFILE_MACHINE_AMD64
JNE .40:
MOV AL,2 ; 2: IMAGE_REL_AMD64_ADDR32.
JSt EBX,relocAbsVA,.70:
INC EAX ; 3: IMAGE_REL_AMD64_ADDR32NB.
JSt EBX,relocAbsRVA,.70:
INC EAX ; 4: IMAGE_REL_AMD64_REL32.
JSt EBX,relocRel,.70:
JMP .E7731:
.40: MOV AL,6 ; 6: IMAGE+REL_I386_DIR32.
JSt EBX,relocAbsVA,.70:
INC EAX ; 7: IMAGE+REL_I386_DIR32NB.
JSt EBX,relocAbsRVA,.70:
MOV AL,20 ; 20: IMAGE_REL_I386_REL32.
JNSt EBX,relocRel,.E7731:
.70: MOV [EDI+PFCOFF_RELOCATION.Type],AX
.80: StreamStore [%Stream],EDI,SIZE# PFCOFF_RELOCATION
.90:EndProcedure PfcoffStreamReloc
FileAlign= and then emitted data and relocations
will be virtually saved to output file at this FA.
FileAlign= alignment.
PfcoffSegmRawData Procedure Segment,Program,FileAddress,SectionHeader,RawBuffer,StringTableBuffer
PgmoptStatus LocalVar ; Local copy of program option Status.
SectionAlign LocalVar ; Local copy of program option SECTIONALIGN=.
FileAlign LocalVar ; Local copy of program option FILEALIGN=.
FirstRelocation LocalVar ; Distance of the 1st PFCOFF_RELOCATION record from %RawBuf.Bottom.
CoffRelocation LocalVar Size=SIZE# PFCOFF_RELOCATION ; Temporary room for one relocation.
MOV EDX,[%Program]
MOV ECX,[EDX+PGM.Pgmopt.SectionAlign]
MOV ESI,[EDX+PGM.Pgmopt.FileAlign]
MOV EAX,[EDX+PGM.Pgmopt.Status]
MOV [%SectionAlign],ECX
MOV [%FileAlign],ESI
MOV [%PgmoptStatus],EAX
MOV EAX,[%FileAddress]
MOV EDI,[%SectionHeader]
MOV EBX,[%Segment]
MOV [%ReturnEAX],EAX ; Initialize returned output FileAddress.
; SectionHeader.Name
MOV ECX,[EBX+SSS.NameSize]
MOV ESI,[EBX+SSS.NamePtr]
LEA EDI,[EDI+PFCOFF_SECTION_HEADER.Name]
CMP ECX,8
JA .15:
.10:REP MOVSB ; Short names go directly to section header.
JMP .25:
.15:MOV EAX,[%StringTableBuffer] ; Longer name is stored to string table.
TEST EAX
JNZ .20: ; Skip when long section names are supported via string table.
Msg '3541',EBX ; Segment name "!1S" is too long, truncated in output file.
MOV ECX,8 ; Executable formats limit segment name size to 8 characters.
JMP .10:
.20:PUSH ECX,ESI
BufferRetrieve EAX ; Get current index to string table.
MOV EDX,ECX ; Remember buffer offset of the free space in StringTableBufer.
POP ESI,ECX
BufferStore EAX,ESI,ECX ; Store long name into the string table.
BufferStoreByte EAX,0 ; Terminating zero.
MOV AL,'/' ; Continue with section header.
STOSB ; Instead of long segment name store /ASCII_offset to section header.Name.
MOV EAX,EDX ; Offset within string table.
StoD EDI,Size=7
.25:MOV EDI,[%SectionHeader]
; SectionHeader.VirtualSize and .VirtualAddress.
JNSt [%PgmoptStatus],pgmoptImage,.30: ; Leave VS and VA at 0 when COFF object file is created.
; Section bottom of executables has already been section-aligned and
; increased by ImageBase in PgmMarshalSegments.
MOV ESI,[EBX+SSS.BottomLow]
MOV ECX,[EBX+SSS.BottomHigh] ; Section bottom ECX:ESI of linkables is always 0.
MOV EDX,[%Program]
PUSH ESI
SUB ESI,[EDX+PGM.Pgmopt.ImageBaseLow] ; Convert VA to RVA.
SBB ECX,[EDX+PGM.Pgmopt.ImageBaseHigh]
MOV [EDI+PFCOFF_SECTION_HEADER.VirtualAddress],ESI
POP ESI
MOV EAX,[EBX+SSS.TopLow]
MOV EDX,[EBX+SSS.TopHigh]
SUB EAX,ESI
SBB EDX,ECX ; EDX:EAX is now the netto data size.
Invoke ExpAlign::,EAX,[%SectionAlign],0 ; VirtualSize will be section-aligned upward, too.
ADD EAX,ECX
MOV [EDI+PFCOFF_SECTION_HEADER.VirtualSize],EAX
.30:MOV ESI,[EBX+SSS.BottomLow] ; Set .SizeOfRawData to section header.
MOV EAX,[EBX+SSS.TopLow]
MOV EDX,[EBX+SSS.TopHigh]
SUB EAX,ESI ; EDX:EAX is now netto section size, both for
SBB EDX,[EBX+SSS.BottomHigh] ; initialized and uninitialized sections.
MOV ECX,EAX ; RawDataSize.
JSt [EBX+SSS.Purpose],sssPurposeInitMask,.35:; Skip if initialized.
JSt [EBX+SSS.Status],sssNotBSS,.35:
JNSt [%PgmoptStatus],pgmoptExecutable,.35: ; Skip if COFF linkable format.
SUB ECX,ECX ; BSS raw size in executable image is 0.
.35:MOV [EDI+PFCOFF_SECTION_HEADER.SizeOfRawData],ECX
JSt [EBX+SSS.Purpose],sssPurposeBSS,.44:
JNSt [EBX+SSS.Status],sssNotBSS,.44: ; BSS section has .PointerToRawData=0.
; Set .PointerToRawData into section header. Raw data must be file-aligned first.
MOV EAX,[%ReturnEAX] ; Current unaligned FA.
Invoke ExpAlign::,EAX,[%FileAlign],0
ADD EAX,ECX
MOV [%ReturnEAX],EAX
MOV [EDI+PFCOFF_SECTION_HEADER.PointerToRawData],EAX
JECXZ .40:
.37:BufferStoreByte [%RawBuffer],0 ; Alignment stuff.
SUB ECX,1
JNZ .37:
.40:BufferRetrieve [EBX+SSS.EmitBuffer] ; Store emitted raw data to aligned RawBuffer.
BufferStore [%RawBuffer],ESI,ECX
ADD [%ReturnEAX],ECX
MOV EAX,[EDI+PFCOFF_SECTION_HEADER.SizeOfRawData] ; Virtual size of raw data.
SUB EAX,ECX ; Compare with emitted size.
JNA .44:
ADD [%ReturnEAX],EAX
BufferResize [%RawBuffer],EAX
.44:JNSt [%PgmoptStatus],pgmoptExecutable,.48: ; COFF object files will have relocations stored.
JNSt [Ea.Eaopt.Status::],eaoptDEBUG,.85: ; No relocation records in PE+DLL when DEBUG=OFF.
.48:; SectionHeader Relocations. Relocation records will be word-aligned.
BufferRetrieve [EBX+SSS.RelocBuffer]
JECXZ .56: ; If there are no relocations in the segment EBX.
.52:JNSt [ESI+RELOC.Status],relocIgnore,.58:
ADD ESI,SIZE# RELOC
SUB ECX,SIZE# RELOC
JA .52:
.56:JMP .85: ; If there are no unresolved relocations in the segment EBX.
.58:; There is at least one unresolved relocation in segment EBX.
MOV EAX,[%ReturnEAX] ; Current unaligned FA. Align it to WORD.
TEST AL,1
JZ .61:
INC EAX
MOV [%ReturnEAX],EAX
BufferStoreByte [%RawBuffer],0
.61:MOV [EDI+PFCOFF_SECTION_HEADER.PointerToRelocations],EAX
BufferRetrieve [%RawBuffer]
MOV [%FirstRelocation],ECX
; ECX is the distance of 1st PFCOFF_RELOCATION record from %RawBuffer.Bottom,
; whose .VirtualAddress might be rewritten later if the number of relocations exceeds 64K.
LEA EDI,[%CoffRelocation] ; EDI points to output COFF format of relocation.
BufferRetrieve [EBX+SSS.RelocBuffer] ; Loop .64: .. .80: through all RELOC records.
.64:JSt [ESI+RELOC.Status],relocIgnore, .75: ; Check if the RELOC record is valid and if it goes to COFF.
PUSH ECX,ESI
MOV EAX,ESI ; Pointer to the input RELOC (internal format of relocation).
MOV ESI,[EAX+RELOC.OrgLow] ; Set RVA of the word/dword/qword which is relocated.
MOV ECX,[EAX+RELOC.OrgHigh]
MOV EDX,[EAX+RELOC.Section]
JECXZ .65:
Msg '7927',EDX,ESI ; Relocation offset out of 4GB range at [!1S]:!2Hh.
JMP .74: ; Ignore invalid relocation.
.65: MOV [EDI+PFCOFF_RELOCATION.VirtualAddress],ESI
; Set the index of COFF section which is the target of relocation.
MOV ECX,[EAX+RELOC.Symbol]
MOV ECX,[ECX+SYM.Section]
SUB EBX,EBX ; Default symbol index is 0, which represents no segment.
JECXZ .67: ; If the symbol was plain number, .SymbolTableIndex=EBX=0.
MOV EBX,[ECX+SSS.NameIndex]
MOV ECX,[ECX+SSS.SegmPtr] ; Segment of relocation target.
JECXZ .67:
MOV EBX,[ECX+SSS.NameIndex]
.67: MOV [EDI+PFCOFF_RELOCATION.SymbolTableIndex],EBX
; Set the type of relocation.
MOV ECX,[%Program]
MOV EBX,[EAX+RELOC.Status]
MOV EDX,[EAX+RELOC.Section]
JSt [ECX+PGM.Pgmopt.Status],pgmoptWidth64,.AMD64:
.I386:; Machine=I386 in 16|32bit programs.
JSt EBX,relocWidth16,.W16:
JSt EBX,relocWidth64,.E7924: ; Invalid relocation.
MOV CX,0x0006 ; IMAGE_REL_I386_DIR32.
JSt EBX,relocAbsVA,.70:
MOV CL,0x0014 ; IMAGE_REL_I386_REL32.
JSt EBX,relocRel,.70:
MOV CL,0x0007 ; IMAGE_REL_I386_DIR32NB.
JSt EBX,relocAbsRVA,.70:
.E7924:POP ESI ; Restore ^RELOC.
PUSH ESI
MOV EDX,[ESI+RELOC.Section]
Msg '7924',[ESI+RELOC.Section],[ESI+RELOC.OrgLow] ; Invalid relocation [!1S]:!2Hh.
JMP .74:
.W16: MOV CX,0x0001 ; IMAGE_REL_I386_DIR16.
JSt EBX,relocAbsVA,.70:
MOV CL,0x0002 ; IMAGE_REL_I386_REL16.
JSt EBX,relocRel,.70:
.AMD64:; Machine=AMD64 in 64bit programs.
MOV CX,0x0004 ; IMAGE_REL_AMD64_REL32.
JSt EBX,relocWidth16,.E7924: ; Invalid relocation [!1S]:!2Hh.
JSt EBX,relocWidth64,.W64:
MOV EAX,relocRelDist
AND EAX,EBX
SHR EAX,24 ; Convert relocRelDist to imm+imm2 size 0..5.
CMP EAX,5
JA .E7924: ; Invalid relocation [!1S]:!2Hh.
ADD CL,AL ; Change reloc type from 0x0004 to 0x0004..0x0009.
JSt EBX,relocRel,.70:
MOV CL,0x0002 ; IMAGE_REL_AMD64_ADDR32.
JSt EBX,relocAbsVA,.70:
MOV CL,0x0003 ; IMAGE_REL_AMD64_ADDR32NB.
JSt EBX,relocAbsRVA,.70:
JMP .E7924: ; Invalid relocation [!1S]:!2Hh.
.W64: MOV CL,0x0001 ; IMAGE_REL_AMD64_ADDR64.
.70: MOV [EDI+PFCOFF_RELOCATION.Type],CX
MOV ECX,SIZE#PFCOFF_RELOCATION
BufferStore [%RawBuffer],EDI,ECX
MOV EDX,[%SectionHeader]
ADD [%ReturnEAX],ECX
INCD [EDX+PFCOFF_SECTION_HEADER.NumberOfRelocations] ; This 16bit counter temporarily misuses
; it's unemployed 16bit neighbour .NumberOfLinenumbers, so the counter is in fact 32bit.
; Word overflow will be healed at .80:.
.74:POP ESI,ECX
.75:ADD ESI,SIZE#RELOC
SUB ECX,SIZE#RELOC
JA .64: ; The next RELOC record.
.80:MOV EDI,[%SectionHeader]
MOV EAX,[EDI+PFCOFF_SECTION_HEADER.NumberOfRelocations]
TEST EAX,0xFFFF0000
JZ .85:
; The .NumberOfRelocations exceeded 64K, design patch will be applied.
BufferRetrieve [%RawBuffer] ; Reread the buffer, as it might get reallocated during BufferStore.
ADD ESI,[%FirstRelocation] ; Find position of the 1st PFCOFF_RELOCATION record in RawBuffer.
; First copy the 1st record to the end.
MOV ECX,SIZE#PFCOFF_RELOCATION
BufferStore [%RawBuffer],ESI,ECX
ADD [%ReturnEAX],ECX
INC EAX ; Increment number of relocations, because one more record was added.
BufferRetrieve [%RawBuffer] ; Reread the buffer, as it might get reallocated during BufferStore.
ADD ESI,[%FirstRelocation] ; Find position of the 1st PFCOFF_RELOCATION record.
MOV [ESI+PFCOFF_RELOCATION.VirtualAddress],EAX ; Real number of relocation, which is above 64K.
MOV EAX,0x0000FFFF
MOVD [EDI+PFCOFF_SECTION_HEADER.NumberOfRelocations],EAX ; Simultaneously clear neighbouring .NumberOfLinenumbers.
SetSt [EDI+PFCOFF_SECTION_HEADER.Characteristics],pfcoffSCN_LNK_NRELOC_OVFL
.85:; Update SectionHeader.Characteristics.
Invoke SssGetCoffCharacteristics::, [%Segment]
SetSt [EDI+PFCOFF_SECTION_HEADER.Characteristics],EAX
EndProcedure PfcoffSegmRawData
ENDPROGRAM pfcoff