home *** CD-ROM | disk | FTP | other *** search
/ Planet Source Code Jumbo …e CD Visual Basic 1 to 7 / 5_2007-2008.ISO / data / Zips / X86_32_Bit209604122008.psc / Editor / ASMBler.cls
Text File  |  2008-01-02  |  67KB  |  1,858 lines

  1. VERSION 1.0 CLASS
  2. BEGIN
  3.   MultiUse = -1  'True
  4.   Persistable = 0  'NotPersistable
  5.   DataBindingBehavior = 0  'vbNone
  6.   DataSourceBehavior  = 0  'vbNone
  7.   MTSTransactionMode  = 0  'NotAnMTSObject
  8. END
  9. Attribute VB_Name = "ASMBler"
  10. Attribute VB_GlobalNameSpace = False
  11. Attribute VB_Creatable = True
  12. Attribute VB_PredeclaredId = False
  13. Attribute VB_Exposed = False
  14. Option Explicit
  15.  
  16.  
  17. ' 32 Bit X86 Assembler
  18. '
  19. ' Arne Elster 2007 / 2008
  20.  
  21.  
  22. ' TODO:
  23. '       * support for instructions like 2-IMUL
  24. '       * more complex expressions for all arguments
  25. '       * Unsigned values (only possible with hex)
  26.  
  27.  
  28. Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
  29.     pDst As Any, pSrc As Any, ByVal cBytes As Long _
  30. )
  31.  
  32.  
  33. Private Const IMAGE_NUMBEROF_DIRECTORY_ENTRIES  As Long = 16&
  34. Private Const IMAGE_SIZEOF_SHORT_NAME           As Long = 8&
  35. Private Const IMAGE_NT_OPTIONAL_HDR32_MAGIC     As Long = &H10B&
  36. Private Const IMAGE_DOS_HDR16_MAGIC             As Long = &H5A4D&
  37. Private Const IMAGE_DOS_HDR32_MAGIC             As Long = &H4550&
  38. Private Const IMAGE_FILE_MACHINE_I386           As Long = &H14C&
  39.  
  40. Private Const DOS_CODE_RELOCATIONS As String = _
  41.         "0E1FBA0E00B409CD21B8014CCD21546869732070726" & _
  42.         "F6772616D2063616E6E6F742062652072756E20696E" & _
  43.         "20444F53206D6F64652E0D0D0A2400000000000000"
  44.  
  45. Private Const MEM_SECTION_SIZE  As Long = 4096
  46. Private Const FILE_SECTION_SIZE As Long = 512
  47.  
  48. Private Const CHAR_SPACE        As Long = 32
  49. Private Const CHAR_LINEFEED     As Long = 10
  50. Private Const CHAR_CARRIAGE     As Long = 13
  51.  
  52. Private Const CHAR_QUOTE        As Long = 34
  53. Private Const CHAR_STOP         As Long = 46
  54. Private Const CHAR_SEMICOLON    As Long = 59
  55. Private Const CHAR_COLON        As Long = 58
  56. Private Const CHAR_PLUS         As Long = 43
  57. Private Const CHAR_MINUS        As Long = 45
  58. Private Const CHAR_ASTERISK     As Long = 42
  59. Private Const CHAR_AMPERSAND    As Long = 38
  60. Private Const CHAR_SEPARATOR    As Long = 44
  61. Private Const CHAR_UNDERSCORE   As Long = 95
  62. Private Const CHAR_VERT_BAR     As Long = 124
  63. Private Const CHAR_SHARP        As Long = 35
  64.  
  65. Private Const CHAR_BRACKET_L    As Long = 91
  66. Private Const CHAR_BRACKET_R    As Long = 93
  67. Private Const CHAR_PARENTH_L    As Long = 40
  68. Private Const CHAR_PARENTH_R    As Long = 41
  69.  
  70. Private Const CHAR_NUMBER_0     As Long = 48
  71. Private Const CHAR_NUMBER_9     As Long = 57
  72.  
  73. Private Const CHAR_ALPHA_UA     As Long = 65
  74. Private Const CHAR_ALPHA_UZ     As Long = 90
  75. Private Const CHAR_ALPHA_LA     As Long = 97
  76. Private Const CHAR_ALPHA_LZ     As Long = 122
  77.  
  78. Private Const REG_COUNT         As Long = 24
  79. Private Const MAX_PARAMETERS    As Long = 3
  80. Private Const MAX_OPCODE_LEN    As Long = 4
  81.  
  82. Public Enum PESubsystem
  83.     Subsystem_GUI = 2
  84.     Subsystem_CUI = 3
  85. End Enum
  86.  
  87. Private Enum SectionCharacteristics
  88.     IMAGE_SCN_TYPE_NO_PAD = &H8&
  89.     IMAGE_SCN_CNT_CODE = &H20&
  90.     IMAGE_SCN_CNT_INITIALIZED_DATA = &H40&
  91.     IMAGE_SCN_CNT_UNINITIALIZED_DATA = &H80&
  92.     IMAGE_SCN_LNK_OTHER = &H100&
  93.     IMAGE_SCN_LNK_INFO = &H200&
  94.     IMAGE_SCN_LNK_REMOVE = &H800&
  95.     IMAGE_SCN_LNK_COMDAT = &H1000&
  96.     IMAGE_SCN_NO_DEFER_SPEC_EXC = &H4000&
  97.     IMAGE_SCN_GPREL = &H8000&
  98.     IMAGE_SCN_MEM_PURGEABLE = &H20000
  99.     IMAGE_SCN_MEM_LOCKED = &H40000
  100.     IMAGE_SCN_MEM_PRELOAD = &H80000
  101.     IMAGE_SCN_LNK_NRELOC_OVFL = &H1000000
  102.     IMAGE_SCN_MEM_DISCARDABLE = &H2000000
  103.     IMAGE_SCN_MEM_NOT_CACHED = &H4000000
  104.     IMAGE_SCN_MEM_NOT_PAGED = &H8000000
  105.     IMAGE_SCN_MEM_SHARED = &H10000000
  106.     IMAGE_SCN_MEM_EXECUTE = &H20000000
  107.     IMAGE_SCN_MEM_READ = &H40000000
  108.     IMAGE_SCN_MEM_WRITE = &H80000000
  109. End Enum
  110.  
  111. Private Enum IMAGE_FILE_CHARACTERISTICS
  112.     IMAGE_FILE_RELOCS_STRIPPED = &H1&
  113.     IMAGE_FILE_EXECUTABLE_IMAGE = &H2&
  114.     IMAGE_FILE_LINE_NUMS_STRIPPED = &H4&
  115.     IMAGE_FILE_LOCAL_SYMS_STRIPPED = &H8&
  116.     IMAGE_FILE_AGGRESSIVE_WS_TRIM = &H10&
  117.     IMAGE_FILE_LARGE_ADDRESS_AWARE = &H20&
  118.     IMAGE_FILE_16BIT_MACHINE = &H40&
  119.     IMAGE_FILE_BYTES_REVERSED_LO = &H80&
  120.     IMAGE_FILE_32BIT_MACHINE = &H100&
  121.     IMAGE_FILE_DEBUG_STRIPPED = &H200&
  122.     IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP = &H400&
  123.     IMAGE_FILE_NET_RUN_FROM_SWAP = &H800&
  124.     IMAGE_FILE_SYSTEM = &H1000&
  125.     IMAGE_FILE_DLL = &H2000&
  126.     IMAGE_FILE_UP_SYSTEM_ONLY = &H4000&
  127.     IMAGE_FILE_BYTES_REVERSED_HI = &H8000&
  128. End Enum
  129.  
  130. Private Enum OptHeaderTbls
  131.     ETableExport = 0
  132.     ETableImport
  133.     ETableResource
  134.     ETableException
  135.     ETableCertificate
  136.     ETableRelocation
  137.     ETableDebug
  138.     ETableArchitecture
  139.     ETableGlobalPtr
  140.     ETableThreadStorage
  141.     ETableLoadConfig
  142.     ETableBoundImport
  143.     ETableIAT
  144.     ETableDelayImportDescriptor
  145.     ETableCOMPlusRuntime
  146.     ETableReserved
  147. End Enum
  148.  
  149. Private Type ModRM
  150.     Mod                         As Long
  151.     rm                          As Long
  152.     reg                         As Long
  153.     Disp                        As Long
  154.     DispSize                    As ParamSize
  155. End Type
  156.  
  157. Private Type SIB
  158.     sscale                      As Long
  159.     index                       As Long
  160.     base                        As Long
  161. End Type
  162.  
  163. Private Type ASMLabel
  164.     Name                        As String
  165.     Instruction                 As Long
  166.     Offset                      As Long
  167. End Type
  168.  
  169. Private Type ASMExtern
  170.     LibName                     As String
  171.     Functions()                 As String
  172.     FunctionCount               As Long
  173. End Type
  174.  
  175. Private Type Pointer
  176.     Registers(REG_COUNT - 1)    As Long
  177.     UsedRegisters               As Long
  178.     Displacement                As Long
  179.     DispSize                    As ParamSize
  180. End Type
  181.  
  182. Private Type PointerInfo
  183.     TokenIndex                  As Long
  184.     RegisterCount               As Long
  185.     RegisterMultiples           As Boolean
  186.     HasDisplacement             As Boolean
  187.     DispSize                    As ParamSize
  188.     ptr                         As Pointer
  189. End Type
  190.  
  191. Private Type RawData
  192.     size                        As ParamSize
  193.     Values()                    As Long
  194.     ValueCount                  As Long
  195. End Type
  196.  
  197. Private Type ASMArgument
  198.     TType                       As ParamType
  199.     size                        As ParamSize
  200.     Pointer                     As PointerInfo
  201.     Register                    As ASMRegisters
  202.     FPURegister                 As ASMFPURegisters
  203.     MMRegister                  As ASMXMMRegisters
  204.     SymbolIndex                 As Long
  205.     Value                       As Long
  206. End Type
  207.  
  208. Private Type ASMInstruction
  209.     Mnemonic                    As String
  210.     Segment                     As ASMSegmentRegs
  211.     Args(MAX_PARAMETERS - 1)    As ASMArgument
  212.     OpCodeIndex                 As Long
  213.     ArgCount                    As Long
  214.     size                        As Long
  215.     Offset                      As Long
  216.     flags                       As OpCodePrefixes
  217.     Data                        As RawData
  218.     Line                        As Long
  219.     Section                     As String
  220. End Type
  221.  
  222. Private Type Scanner
  223.     Source()                    As Byte
  224.     Length                      As Long
  225.     Position                    As Long
  226.     Line                        As Long
  227.     LinePos                     As Long
  228.     Section                     As String
  229.     NextIsEOI                   As Boolean
  230.     LastWasEOI                  As Boolean
  231.     NextToken                   As ASMToken
  232.     CurToken                    As ASMToken
  233. End Type
  234.  
  235. Private Type IMAGE_IMPORT_DIRECTORY
  236.     ImportLookupTable           As Long
  237.     TimeDateStamp               As Long
  238.     ForwardChain                As Long
  239.     ModuleName                  As Long
  240.     ImportAddressTable          As Long
  241. End Type
  242.  
  243. Private Type IMAGE_DATA_DIRECTORY
  244.     VirtualAddress              As Long
  245.     size                        As Long
  246. End Type
  247.  
  248. Private Type IMAGE_SECTION_HEADER
  249.     SectionName(IMAGE_SIZEOF_SHORT_NAME - 1) As Byte
  250.     VirtSizePhysAddr            As Long
  251.     VirtualAddress              As Long
  252.     SizeOfRawData               As Long
  253.     PointerToRawData            As Long
  254.     PointerToRelocations        As Long
  255.     PointerToLinenumbers        As Long
  256.     NumberOfRelocations         As Integer
  257.     NumberOfLinenumbers         As Integer
  258.     Characteristics             As Long
  259. End Type
  260.  
  261. Private Type IMAGE_OPTIONAL_HEADER
  262.     Magic                       As Integer
  263.     MajorLinkerVersion          As Byte
  264.     MinorLinkerVersion          As Byte
  265.     SizeOfCode                  As Long
  266.     SizeOfInitializedData       As Long
  267.     SizeOfUninitializedData     As Long
  268.     AddressOfEntryPoint         As Long
  269.     BaseOfCode                  As Long
  270.     BaseOfData                  As Long
  271.     ImageBase                   As Long
  272.     SectionAlignment            As Long
  273.     FileAlignment               As Long
  274.     MajorOperatingSystemVersion As Integer
  275.     MinorOperatingSystemVersion As Integer
  276.     MajorImageVersion           As Integer
  277.     MinorImageVersion           As Integer
  278.     MajorSubsystemVersion       As Integer
  279.     MinorSubsystemVersion       As Integer
  280.     Win32VersionValue           As Long
  281.     SizeOfImage                 As Long
  282.     SizeOfHeaders               As Long
  283.     CheckSum                    As Long
  284.     Subsystem                   As Integer
  285.     DllCharacteristics          As Integer
  286.     SizeOfStackReserve          As Long
  287.     SizeOfStackCommit           As Long
  288.     SizeOfHeapReserve           As Long
  289.     SizeOfHeapCommit            As Long
  290.     LoaderFlags                 As Long
  291.     NumberOfRvaAndSizes         As Long
  292.     DataDirectory(IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1)  As IMAGE_DATA_DIRECTORY
  293. End Type
  294.  
  295. Private Type IMAGE_DOS_HEADER
  296.     Magic                       As Integer
  297.     BytesInLastPage             As Integer
  298.     Pages                       As Integer
  299.     Relocations                 As Integer
  300.     ParagraphsInHeader          As Integer
  301.     MinAlloc                    As Integer
  302.     MaxAlloc                    As Integer
  303.     InitialSS                   As Integer
  304.     InitialSP                   As Integer
  305.     CheckSum                    As Integer
  306.     InitialIP                   As Integer
  307.     InitialCS                   As Integer
  308.     RelocationTableFileAddress  As Integer
  309.     OverlayNumber               As Integer
  310.     Reserved1(3)                As Integer
  311.     OEMIdentifier               As Integer
  312.     OEMInformation              As Integer
  313.     Reserved2(9)                As Integer
  314.     NewHeaderOffset             As Long
  315. End Type
  316.  
  317. Private Type IMAGE_FILE_HEADER
  318.     Machine                     As Integer
  319.     NumberOfSections            As Integer
  320.     TimeDateStamp               As Long
  321.     PointerToSymbolTable        As Long
  322.     NumberOfSymbols             As Long
  323.     SizeOfOptionalHeader        As Integer
  324.     Characteristics             As Integer
  325. End Type
  326.  
  327. Private Type IMAGE_NT_HEADERS
  328.     Signature                   As Long
  329.     FileHeader                  As IMAGE_FILE_HEADER
  330.     OptionalHeader              As IMAGE_OPTIONAL_HEADER
  331. End Type
  332.  
  333. Private m_udtScanner            As Scanner
  334.  
  335. Private m_clsTokens()           As ASMToken
  336. Private m_lngTokenCount         As Long
  337. Private m_lngCurToken           As Long
  338.  
  339. Private m_udtLabels()           As ASMLabel
  340. Private m_lngLabelCount         As Long
  341.  
  342. Private m_udtExtern()           As ASMExtern
  343. Private m_lngExternCount        As Long
  344.  
  345. Private m_udtInstrs()           As ASMInstruction
  346. Private m_lngInstrCount         As Long
  347.  
  348. Private m_strLastError          As String
  349. Private m_strLastErrorSection   As String
  350. Private m_lngLastErrLine        As Long
  351.  
  352. Private m_btOutput()            As Byte
  353. Private m_lngOutSize            As Long
  354. Private m_lngOutPos             As Long
  355.  
  356. Private m_udeSubsystem          As PESubsystem
  357.  
  358. Private m_blnWritePE            As Boolean
  359. Private m_lngPECodeSize         As Long
  360.  
  361. Private m_lngBaseAddress        As Long
  362.  
  363.  
  364. Private Sub Class_Initialize()
  365.     InitInstructions
  366.     m_udeSubsystem = Subsystem_CUI
  367. End Sub
  368.  
  369.  
  370. Public Property Get Subsystem() As PESubsystem
  371.     Subsystem = m_udeSubsystem
  372. End Property
  373.  
  374.  
  375. Public Property Let Subsystem(ByVal lngVal As PESubsystem)
  376.     m_udeSubsystem = lngVal
  377. End Property
  378.  
  379.  
  380. Public Property Get PEHeader() As Boolean
  381.     PEHeader = m_blnWritePE
  382. End Property
  383.  
  384.  
  385. Public Property Let PEHeader(ByVal blnValue As Boolean)
  386.     m_blnWritePE = blnValue
  387. End Property
  388.  
  389.  
  390. Public Property Get BaseAddress() As Long
  391.     BaseAddress = m_lngBaseAddress
  392. End Property
  393.  
  394.  
  395. Public Property Let BaseAddress(ByVal lngVal As Long)
  396.     m_lngBaseAddress = lngVal
  397.     If m_lngBaseAddress < 0 Then Err.Raise 6, , "Image Base < 0 invalid"
  398. End Property
  399.  
  400.  
  401. Public Property Get LastErrorMessage() As String
  402.     LastErrorMessage = m_strLastError
  403. End Property
  404.  
  405.  
  406. Public Property Get LastErrorSection() As String
  407.     LastErrorSection = m_strLastErrorSection
  408. End Property
  409.  
  410.  
  411. Public Property Get LastErrorLine() As Long
  412.     LastErrorLine = m_lngLastErrLine
  413. End Property
  414.  
  415.  
  416. Public Function GetOutput() As Byte()
  417.     GetOutput = m_btOutput
  418. End Function
  419.  
  420.  
  421. Public Property Get OutputSize() As Long
  422.     OutputSize = m_lngOutSize
  423. End Property
  424.  
  425.  
  426. ' 1. tokenize the input string
  427. ' 2. collect all labels
  428. ' 3. find all instructions
  429. ' 4. find OpCodes for instructions
  430. '    get their sizes and calculate label offsets
  431. ' 5. now that the label offsets are known,
  432. '    finally parse pointers
  433. ' 6. write instructions to output
  434. ' 7. if in PE mode, write IAT (import address table)
  435. Public Function Assemble( _
  436.     strASM As String, _
  437.     Optional ByVal OnlySize As Boolean = False _
  438. ) As Boolean
  439.  
  440.     ScannerInit strASM
  441.     
  442.     m_lngTokenCount = 0
  443.     m_lngLabelCount = 0
  444.     m_lngInstrCount = 0
  445.     m_lngCurToken = 0
  446.     m_lngOutSize = 0
  447.     m_lngOutPos = 0
  448.     m_lngExternCount = 0
  449.     
  450.     m_strLastError = ""
  451.     m_lngLastErrLine = 0
  452.     
  453.     TokenizeInput
  454.     
  455.     If FindLabels() Then
  456.         If ParseInstructions() Then
  457.             If GetInstructionSizes() Then
  458.                 If OnlySize Then
  459.                     Assemble = True
  460.                 Else
  461.                     If ParsePointers() Then
  462.                         If m_blnWritePE Then
  463.                             If Not WritePEHeader() Then Exit Function
  464.                         End If
  465.                         
  466.                         If AssembleInstructions() Then
  467.                             If m_blnWritePE Then
  468.                                 OutputJumpTo RoundToMinSize(OutputPosition)
  469.                                 WritePEImports
  470.                             End If
  471.                             Assemble = True
  472.                         End If
  473.                     End If
  474.                 End If
  475.             End If
  476.         End If
  477.     End If
  478. End Function
  479.  
  480.  
  481. Private Sub WritePEImports()
  482.     Dim lngRVAIAT   As Long
  483.     Dim ntHdr       As IMAGE_NT_HEADERS
  484.     Dim scHdr       As IMAGE_SECTION_HEADER
  485.     
  486.     Const SECTIONS = 2
  487.     
  488.     lngRVAIAT = RoundToSectionSize(Len(ntHdr) + Len(scHdr) * SECTIONS)
  489.     lngRVAIAT = lngRVAIAT + RoundToSectionSize(m_lngPECodeSize)
  490.     
  491.     WriteIAT lngRVAIAT
  492.     WriteIIDs lngRVAIAT
  493.     WriteIAT lngRVAIAT
  494.     WriteImportedNames
  495. End Sub
  496.  
  497.  
  498. Private Sub WriteImportedNames()
  499.     Dim i       As Long
  500.     Dim j       As Long
  501.     
  502.     For i = 0 To m_lngExternCount - 1
  503.         For j = 0 To m_udtExtern(i).FunctionCount - 1
  504.             OutputInteger 0
  505.             WriteStr0Ev m_udtExtern(i).Functions(j)
  506.         Next
  507.         WriteStr0Ev m_udtExtern(i).LibName
  508.     Next
  509. End Sub
  510.  
  511.  
  512. Private Sub WriteStr0Ev(ByVal strN As String)
  513.     Dim btN()   As Byte
  514.     
  515.     btN = StrConv(strN & ChrW$(0), vbFromUnicode)
  516.     OutputMem VarPtr(btN(0)), UBound(btN) + 1
  517.     
  518.     If (UBound(btN) + 1) Mod 2 = 1 Then
  519.         OutputByte 0
  520.     End If
  521. End Sub
  522.  
  523.  
  524. Private Sub WriteIIDs(ByVal base As Long)
  525.     Dim i       As Long
  526.     Dim j       As Long
  527.     Dim im      As IMAGE_IMPORT_DIRECTORY
  528.     Dim eim     As IMAGE_IMPORT_DIRECTORY
  529.     
  530.     For i = 0 To m_lngExternCount - 1
  531.         With im
  532.             .ModuleName = base + GetRelOfLibname(i)
  533.             .ImportAddressTable = base + GetIATLibStart(i)
  534.             .ImportLookupTable = base + GetILTLibStart(i)
  535.         End With
  536.         
  537.         OutputMem VarPtr(im), Len(im)
  538.     Next
  539.     
  540.     OutputMem VarPtr(eim), Len(eim)
  541. End Sub
  542.  
  543.  
  544. Private Sub WriteIAT(ByVal base As Long)
  545.     Dim i   As Long
  546.     Dim j   As Long
  547.     
  548.     For i = 0 To m_lngExternCount - 1
  549.         For j = 0 To m_udtExtern(i).FunctionCount - 1
  550.             OutputLong base + GetRelOfFncname(i, j)
  551.         Next
  552.         OutputLong 0
  553.     Next
  554. End Sub
  555.  
  556.  
  557. ' address of a function name in the imports section
  558. ' relative to the section's start
  559. Private Function GetRelOfFncname(ByVal libdx As Long, ByVal fncidx As Long) As Long
  560.     Dim i   As Long
  561.     Dim j   As Long
  562.     Dim sz  As Long
  563.     Dim im  As IMAGE_IMPORT_DIRECTORY
  564.     
  565.     For i = 0 To m_lngExternCount - 1
  566.         sz = sz + 4 * (m_udtExtern(i).FunctionCount + 1) * 2
  567.         sz = sz + Len(im)
  568.     Next
  569.     If m_lngExternCount > 0 Then sz = sz + Len(im)
  570.     
  571.     For i = 0 To m_lngExternCount - 1
  572.         For j = 0 To m_udtExtern(i).FunctionCount - 1
  573.             If (i = libdx) And (j = fncidx) Then
  574.                 GetRelOfFncname = sz
  575.                 Exit Function
  576.             Else
  577.                 sz = sz + 2 + EvenSize(Len(m_udtExtern(i).Functions(j)) + 1)
  578.             End If
  579.         Next
  580.         sz = sz + EvenSize(Len(m_udtExtern(i).LibName) + 1)
  581.     Next
  582. End Function
  583.  
  584.  
  585. ' address of a library name in the imports section
  586. ' relative to the section's start
  587. Private Function GetRelOfLibname(ByVal index As Long) As Long
  588.     Dim i   As Long
  589.     Dim j   As Long
  590.     Dim sz  As Long
  591.     Dim im  As IMAGE_IMPORT_DIRECTORY
  592.     
  593.     For i = 0 To m_lngExternCount - 1
  594.         sz = sz + 4 * (m_udtExtern(i).FunctionCount + 1) * 2
  595.         sz = sz + Len(im)
  596.     Next
  597.     If m_lngExternCount > 0 Then sz = sz + Len(im)
  598.     
  599.     For i = 0 To m_lngExternCount - 1
  600.         For j = 0 To m_udtExtern(i).FunctionCount - 1
  601.             sz = sz + 2 + EvenSize(Len(m_udtExtern(i).Functions(j)) + 1)
  602.         Next
  603.         
  604.         If i <> index Then
  605.             sz = sz + EvenSize(Len(m_udtExtern(i).LibName) + 1)
  606.         Else
  607.             Exit For
  608.         End If
  609.     Next
  610.     
  611.     GetRelOfLibname = sz
  612. End Function
  613.  
  614.  
  615. Private Function WritePEHeader() As Boolean
  616.     Dim mzHdr   As IMAGE_DOS_HEADER
  617.     Dim ntHdr   As IMAGE_NT_HEADERS
  618.     Dim scHdr   As IMAGE_SECTION_HEADER
  619.     Dim sdHdr   As IMAGE_SECTION_HEADER
  620.     Dim impTbl  As IMAGE_IMPORT_DIRECTORY
  621.     Dim lngImp  As Long
  622.     Dim btDOS() As Byte
  623.     
  624.     Const SECTIONS = 2
  625.     
  626.     If GetLabelIndex("MAIN") = -1 Then
  627.         SetError "Entrypoint ""Main"" not found.", 0, ""
  628.         Exit Function
  629.     End If
  630.     
  631.     lngImp = GetNeededImportsSize()
  632.     If lngImp = 0 Then lngImp = 1
  633.     
  634.     With mzHdr
  635.         .Magic = IMAGE_DOS_HDR16_MAGIC
  636.         .BytesInLastPage = 144
  637.         .Pages = 3
  638.         .ParagraphsInHeader = 4
  639.         .MaxAlloc = &HFFFF
  640.         .InitialSP = &HB8
  641.         .RelocationTableFileAddress = &H40
  642.         .NewHeaderOffset = Len(mzHdr) + 64
  643.     End With
  644.       
  645.     With ntHdr
  646.         .Signature = IMAGE_DOS_HDR32_MAGIC
  647.         
  648.         With .FileHeader
  649.             .Machine = IMAGE_FILE_MACHINE_I386
  650.             .NumberOfSections = SECTIONS
  651.             .SizeOfOptionalHeader = Len(ntHdr.OptionalHeader)
  652.             .Characteristics = IMAGE_FILE_RELOCS_STRIPPED Or IMAGE_FILE_LINE_NUMS_STRIPPED Or _
  653.                                IMAGE_FILE_LOCAL_SYMS_STRIPPED Or IMAGE_FILE_EXECUTABLE_IMAGE Or _
  654.                                IMAGE_FILE_32BIT_MACHINE Or IMAGE_FILE_DEBUG_STRIPPED Or _
  655.                                IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP Or IMAGE_FILE_NET_RUN_FROM_SWAP
  656.         End With
  657.         
  658.         With .OptionalHeader
  659.             .Magic = IMAGE_NT_OPTIONAL_HDR32_MAGIC
  660.             .SizeOfCode = RoundToMinSize(m_lngPECodeSize)
  661.             .SizeOfInitializedData = RoundToMinSize(lngImp)
  662.             .BaseOfCode = RoundToSectionSize(Len(ntHdr) + Len(scHdr) * SECTIONS)
  663.             .BaseOfData = .BaseOfCode + RoundToSectionSize(.SizeOfCode)
  664.             .AddressOfEntryPoint = m_udtLabels(GetLabelIndex("MAIN")).Offset - m_lngBaseAddress
  665.             .ImageBase = m_lngBaseAddress
  666.             .SectionAlignment = MEM_SECTION_SIZE
  667.             .FileAlignment = FILE_SECTION_SIZE
  668.             .MajorOperatingSystemVersion = 4
  669.             .MajorSubsystemVersion = 4
  670.             .SizeOfImage = .BaseOfData + RoundToSectionSize(lngImp)
  671.             .SizeOfHeaders = GetPEHeaderSize()
  672.             .Subsystem = m_udeSubsystem
  673.             .SizeOfStackReserve = &H100000
  674.             .SizeOfStackCommit = &H1000
  675.             .SizeOfHeapReserve = &H100000
  676.             .SizeOfHeapCommit = &H1000
  677.             .NumberOfRvaAndSizes = 16
  678.             
  679.             With .DataDirectory(ETableImport)
  680.                 .VirtualAddress = ntHdr.OptionalHeader.BaseOfCode + _
  681.                                   RoundToSectionSize(ntHdr.OptionalHeader.SizeOfCode) + _
  682.                                   GetNeededIATSize()
  683.                                   
  684.                 .size = Len(impTbl)
  685.             End With
  686.             
  687.             With .DataDirectory(ETableIAT)
  688.                 .VirtualAddress = ntHdr.OptionalHeader.BaseOfCode + _
  689.                                   RoundToSectionSize(ntHdr.OptionalHeader.SizeOfCode)
  690.                                   
  691.                 .size = GetNeededIATSize()
  692.             End With
  693.         End With
  694.     End With
  695.     
  696.     With scHdr
  697.         WriteSectionName scHdr, ".text"
  698.         .VirtSizePhysAddr = m_lngPECodeSize
  699.         .VirtualAddress = ntHdr.OptionalHeader.BaseOfCode
  700.         .SizeOfRawData = RoundToMinSize(m_lngPECodeSize)
  701.         .PointerToRawData = GetPEHeaderSize()
  702.         .Characteristics = IMAGE_SCN_CNT_CODE Or _
  703.                            IMAGE_SCN_MEM_EXECUTE Or _
  704.                            IMAGE_SCN_MEM_READ Or _
  705.                            IMAGE_SCN_MEM_WRITE
  706.     End With
  707.     
  708.     With sdHdr
  709.         WriteSectionName sdHdr, ".rdata"
  710.         .VirtSizePhysAddr = lngImp
  711.         .VirtualAddress = ntHdr.OptionalHeader.BaseOfData
  712.         .SizeOfRawData = RoundToMinSize(lngImp)
  713.         .PointerToRawData = scHdr.PointerToRawData + scHdr.SizeOfRawData
  714.         .Characteristics = IMAGE_SCN_MEM_READ Or _
  715.                            IMAGE_SCN_MEM_WRITE
  716.     End With
  717.     
  718.     btDOS = HexToByte(DOS_CODE_RELOCATIONS)
  719.     
  720.     OutputMem VarPtr(mzHdr), Len(mzHdr)
  721.     OutputMem VarPtr(btDOS(0)), UBound(btDOS) + 1
  722.     OutputMem VarPtr(ntHdr), Len(ntHdr)
  723.     OutputMem VarPtr(scHdr), Len(scHdr)
  724.     OutputMem VarPtr(sdHdr), Len(sdHdr)
  725.     
  726.     OutputJumpTo RoundToMinSize(OutputPosition)
  727.     
  728.     WritePEHeader = True
  729. End Function
  730.  
  731.  
  732. Private Sub WriteSectionName(sc As IMAGE_SECTION_HEADER, ByVal strName As String)
  733.     Dim i   As Long
  734.     
  735.     For i = 1 To Len(strName)
  736.         sc.SectionName(i - 1) = Asc(Mid$(strName, i, 1))
  737.     Next
  738. End Sub
  739.  
  740.  
  741. Private Function GetPEHeaderSize() As Long
  742.     Dim mzHdr   As IMAGE_DOS_HEADER
  743.     Dim ntHdr   As IMAGE_NT_HEADERS
  744.     Dim scHdr   As IMAGE_SECTION_HEADER
  745.     
  746.     Const SECTIONS = 2
  747.     
  748.     GetPEHeaderSize = RoundToMinSize(Len(mzHdr) + 64 + Len(ntHdr) + Len(scHdr) * SECTIONS)
  749. End Function
  750.  
  751.  
  752. ' every instruction has prefixes (opt), an opcode and arguments (opt).
  753. ' write them to the output
  754. Private Function AssembleInstructions() As Boolean
  755.     Dim i       As Long
  756.     Dim lngSz   As Long
  757.     
  758.     For i = 0 To m_lngInstrCount - 1
  759.         lngSz = m_lngOutPos
  760.         
  761.         If m_udtInstrs(i).Data.size <> BitsUnknown Then
  762.             If Not RawDataOut(m_udtInstrs(i).Data) Then Exit Function
  763.         Else
  764.             InstructionOutPrefixes m_udtInstrs(i)
  765.             InstructionOutOpCode m_udtInstrs(i)
  766.             If Not InstructionOutArgs(m_udtInstrs(i)) Then Exit Function
  767.         End If
  768.         
  769.         lngSz = m_lngOutPos - lngSz
  770.         If lngSz <> m_udtInstrs(i).size Then Err.Raise 123, , "invalid size after output"
  771.     Next
  772.     
  773.     AssembleInstructions = True
  774. End Function
  775.  
  776.  
  777. ' db, dw, dd strings
  778. Private Function RawDataOut(Data As RawData) As Boolean
  779.     Dim i   As Long
  780.     
  781.     For i = 0 To Data.ValueCount - 1
  782.         OutputBytes Data.Values(i), Data.size
  783.     Next
  784.     
  785.     RawDataOut = True
  786. End Function
  787.  
  788.  
  789. ' write arguments to output (modR/M, SIB, Pointers, ...)
  790. ' SIB is only written when a pointer has more then 2 registers
  791. ' or multiples of a register, or when ESP is used.
  792. Private Function InstructionOutArgs(udtInstr As ASMInstruction) As Boolean
  793.     Dim i               As Long
  794.     Dim j               As Long
  795.     
  796.     Dim udtModRM        As ModRM
  797.     Dim blnModRM        As Boolean
  798.     Dim blnSIBNeeded    As Boolean
  799.     
  800.     Dim lngImmVal()     As Long
  801.     Dim udeImmSize()    As ParamSize
  802.     Dim lngImmValCnt    As Long
  803.     Dim blnImmVal       As Boolean
  804.     
  805.     Dim lngDisplacement As Long
  806.     Dim udeDispSize     As ParamSize
  807.     Dim blnDisplacement As Boolean
  808.     
  809.     Dim lngSIBPtrIdx    As Long
  810.     
  811.     Dim blnGotXMMReg    As Boolean
  812.     Dim lngMMVal        As Long
  813.     
  814.     With Instructions(udtInstr.OpCodeIndex)
  815.         blnModRM = .ModRM
  816.         If .RegOpExt > -1 Then
  817.             udtModRM.reg = .RegOpExt
  818.             blnGotXMMReg = True
  819.         End If
  820.     End With
  821.     
  822.     For i = 0 To udtInstr.ArgCount - 1
  823.         With Instructions(udtInstr.OpCodeIndex).Parameters(i)
  824.             If Not .Forced Then
  825.             
  826.                 If (.PType = ParamImm) Or (.PType = ParamRel) Then
  827.                     ' an instruction can have multiple immediates
  828.                     ReDim Preserve lngImmVal(lngImmValCnt) As Long
  829.                     ReDim Preserve udeImmSize(lngImmValCnt) As ParamSize
  830.                     
  831.                     If udtInstr.Args(i).TType = ParamImm Then
  832.                         lngImmVal(lngImmValCnt) = udtInstr.Args(i).Value
  833.                     ElseIf udtInstr.Args(i).TType = ParamRel Then
  834.                         lngImmVal(lngImmValCnt) = m_udtLabels(udtInstr.Args(i).SymbolIndex).Offset
  835.                     End If
  836.                     
  837.                     If .PType = ParamRel Then
  838.                         ' if a relative value is needed, make the immediate
  839.                         ' relative to the end of the current instruction
  840.                         lngImmVal(lngImmValCnt) = lngImmVal(lngImmValCnt) - (udtInstr.Offset + udtInstr.size)
  841.                     End If
  842.                     
  843.                     If (SizesForInt(lngImmVal(lngImmValCnt)) And .size) = 0 Then
  844.                         SetError "Relative value too big for instruction", udtInstr.Line, udtInstr.Section
  845.                         Exit Function
  846.                     End If
  847.                     
  848.                     udeImmSize(lngImmValCnt) = .size
  849.                     lngImmValCnt = lngImmValCnt + 1
  850.                     blnImmVal = True
  851.                     
  852.                 ElseIf .PType = ParamReg Then
  853.                     ' register must be put to ModR/M, else it would be "forced"
  854.                     udtModRM.reg = ModRMRegNum(udtInstr.Args(i).Register)
  855.                 
  856.                 ElseIf .PType = ParamMM Then
  857.                     Select Case udtInstr.Args(i).MMRegister
  858.                         Case MM0, XMM0: lngMMVal = 0
  859.                         Case MM1, XMM1: lngMMVal = 1
  860.                         Case MM2, XMM2: lngMMVal = 2
  861.                         Case MM3, XMM3: lngMMVal = 3
  862.                         Case MM4, XMM4: lngMMVal = 4
  863.                         Case MM5, XMM5: lngMMVal = 5
  864.                         Case MM6, XMM6: lngMMVal = 6
  865.                         Case MM7, XMM7: lngMMVal = 7
  866.                     End Select
  867.                     
  868.                     If blnGotXMMReg Then
  869.                         udtModRM.Mod = 3
  870.                         udtModRM.rm = lngMMVal
  871.                     Else
  872.                         udtModRM.reg = lngMMVal
  873.                         blnGotXMMReg = True
  874.                     End If
  875.                 
  876.                 ElseIf (.PType = (ParamMem Or ParamReg)) Or _
  877.                        (.PType = (ParamMem Or ParamMM)) Or _
  878.                        (.PType = ParamMem) Then
  879.                        
  880.                     If (.PType = ParamMem) And (Not blnModRM) Then
  881.                         ' !#! cann there also be more than one per instruction? !#!
  882.                         lngDisplacement = udtInstr.Args(i).Pointer.ptr.Displacement
  883.                         udeDispSize = Bits32
  884.                         blnDisplacement = True
  885.                     Else
  886.                         If udtInstr.Args(i).TType = ParamMem Then
  887.                             Select Case udtInstr.Args(i).Pointer.RegisterCount
  888.                                 Case 0:
  889.                                     ' no reigster in the pointer, only displacement possible
  890.                                     If udtInstr.Args(i).Pointer.HasDisplacement Then
  891.                                         udtModRM.Disp = udtInstr.Args(i).Pointer.ptr.Displacement
  892.                                         udtModRM.DispSize = Bits32
  893.                                         udtModRM.Mod = 0
  894.                                         udtModRM.rm = 5
  895.                                     End If
  896.                                     
  897.                                 Case 1:
  898.                                     ' 1 Register in the pointer, can be encoded with ModR/M
  899.                                     ' if its not ESP or a multiple (reg*2/3/4/5/8/9)
  900.                                     If udtInstr.Args(i).Pointer.HasDisplacement Then
  901.                                         udtModRM.Disp = udtInstr.Args(i).Pointer.ptr.Displacement
  902.                                         udtModRM.DispSize = udtInstr.Args(i).Pointer.ptr.DispSize
  903.                                         Select Case udtModRM.DispSize
  904.                                             Case Bits8:     udtModRM.Mod = 1
  905.                                             Case Else:      udtModRM.Mod = 2
  906.                                         End Select
  907.                                     Else
  908.                                         udtModRM.Mod = 0
  909.                                     End If
  910.                                     
  911.                                     For j = 0 To REG_COUNT - 1
  912.                                         If udtInstr.Args(i).Pointer.ptr.Registers(j) Then
  913.                                             If udtInstr.Args(i).Pointer.ptr.Registers(j) > 1 Then
  914.                                                 blnSIBNeeded = True
  915.                                                 lngSIBPtrIdx = i
  916.                                             Else
  917.                                                 Select Case IdxToReg(j)
  918.                                                     Case RegEAX: udtModRM.rm = 0
  919.                                                     Case RegECX: udtModRM.rm = 1
  920.                                                     Case RegEDX: udtModRM.rm = 2
  921.                                                     Case RegEBX: udtModRM.rm = 3
  922.                                                     Case RegEBP: udtModRM.rm = 5
  923.                                                     Case RegESI: udtModRM.rm = 6
  924.                                                     Case RegEDI: udtModRM.rm = 7
  925.                                                     Case RegESP: blnSIBNeeded = True
  926.                                                                  lngSIBPtrIdx = i
  927.                                                 End Select
  928.                                             End If
  929.                                             
  930.                                             Exit For
  931.                                         End If
  932.                                     Next
  933.                                     
  934.                                 Case 2:
  935.                                     ' 2 registers, SIB needed
  936.                                     If udtInstr.Args(i).Pointer.HasDisplacement Then
  937.                                         udtModRM.Disp = udtInstr.Args(i).Pointer.ptr.Displacement
  938.                                         udtModRM.DispSize = udtInstr.Args(i).Pointer.ptr.DispSize
  939.                                         Select Case udtModRM.DispSize
  940.                                             Case Bits8:     udtModRM.Mod = 1
  941.                                             Case Else:      udtModRM.Mod = 2
  942.                                         End Select
  943.                                     Else
  944.                                         udtModRM.Mod = 0
  945.                                     End If
  946.                                     
  947.                                     blnSIBNeeded = True
  948.                                     lngSIBPtrIdx = i
  949.                                     
  950.                             End Select
  951.                             
  952.                         ElseIf udtInstr.Args(i).TType = ParamReg Then
  953.                             ' encode second register in ModR/M
  954.                             udtModRM.Mod = 3
  955.                             udtModRM.rm = ModRMRegNum(udtInstr.Args(i).Register)
  956.                         
  957.                         ElseIf udtInstr.Args(i).TType = (ParamMem Or ParamExt) Then
  958.                             lngDisplacement = udtInstr.Args(i).Pointer.ptr.Displacement
  959.                             udeDispSize = Bits32
  960.                             udtModRM.rm = 5
  961.                             blnDisplacement = True
  962.                         
  963.                         ElseIf udtInstr.Args(i).TType = ParamMM Then
  964.                             Select Case udtInstr.Args(i).MMRegister
  965.                                 Case MM0, XMM0: udtModRM.rm = 0
  966.                                 Case MM1, XMM1: udtModRM.rm = 1
  967.                                 Case MM2, XMM2: udtModRM.rm = 2
  968.                                 Case MM3, XMM3: udtModRM.rm = 3
  969.                                 Case MM4, XMM4: udtModRM.rm = 4
  970.                                 Case MM5, XMM5: udtModRM.rm = 5
  971.                                 Case MM6, XMM6: udtModRM.rm = 6
  972.                                 Case MM7, XMM7: udtModRM.rm = 7
  973.                             End Select
  974.                             udtModRM.Mod = 3
  975.                         
  976.                         End If
  977.                     End If
  978.                     
  979.                 End If
  980.                 
  981.             End If
  982.         End With
  983.     Next
  984.     
  985.     If blnSIBNeeded Then
  986.         udtModRM.rm = 4
  987.         If Not WriteSIB(udtInstr, udtModRM, udtInstr.Args(lngSIBPtrIdx).Pointer.ptr) Then
  988.             Exit Function
  989.         End If
  990.     Else
  991.         If blnModRM Then WriteModRM udtModRM
  992.     End If
  993.     
  994.     If blnDisplacement Then OutputBytes lngDisplacement, udeDispSize
  995.     If blnImmVal Then
  996.         For i = 0 To lngImmValCnt - 1
  997.             OutputBytes lngImmVal(i), udeImmSize(i)
  998.         Next
  999.     End If
  1000.     
  1001.     If Instructions(udtInstr.OpCodeIndex).Now3DByte > -1 Then
  1002.         OutputByte Instructions(udtInstr.OpCodeIndex).Now3DByte
  1003.     End If
  1004.     
  1005.     InstructionOutArgs = True
  1006. End Function
  1007.  
  1008.  
  1009. Private Function WriteSIB( _
  1010.     udtInstr As ASMInstruction, _
  1011.     rm As ModRM, _
  1012.     ptr As Pointer _
  1013. ) As Boolean
  1014.  
  1015.     Dim udtSIB          As SIB
  1016.     Dim udeReg(1)       As ASMRegisters
  1017.     Dim lngRegCnt(1)    As Long
  1018.     Dim lngScale        As Long
  1019.     Dim lngBase         As Long
  1020.     Dim i               As Long
  1021.     Dim j               As Long
  1022.     
  1023.     ' find the used registers
  1024.     For i = 0 To REG_COUNT - 1
  1025.         If ptr.Registers(i) Then
  1026.             udeReg(j) = IdxToReg(i)
  1027.             lngRegCnt(j) = ptr.Registers(i)
  1028.             j = j + 1
  1029.         End If
  1030.     Next
  1031.     
  1032.     ' determine the scale register (can have a multiple)
  1033.     If lngRegCnt(0) >= 1 And lngRegCnt(1) = 1 Then
  1034.         lngScale = 0
  1035.     ElseIf lngRegCnt(1) >= 1 And lngRegCnt(0) = 1 Then
  1036.         lngScale = 1
  1037.     End If
  1038.     ' the base register is the other one ;)
  1039.     lngBase = 1 - lngScale
  1040.     
  1041.     If (ptr.UsedRegisters = 1) And (lngRegCnt(0) = 1) Then
  1042.         ' olny one register used which isn't a multiple
  1043.         udtSIB.sscale = 0
  1044.         udtSIB.index = 4
  1045.         
  1046.         Select Case udeReg(0)
  1047.             Case RegEAX:    udtSIB.base = 0
  1048.             Case RegECX:    udtSIB.base = 1
  1049.             Case RegEDX:    udtSIB.base = 2
  1050.             Case RegEBX:    udtSIB.base = 3
  1051.             Case RegESP:    udtSIB.base = 4  ' <= all the others encodable in ModR/M
  1052.             Case RegEBP:    udtSIB.base = 5
  1053.             Case RegESI:    udtSIB.base = 6
  1054.             Case RegEDI:    udtSIB.base = 7
  1055.         End Select
  1056.         
  1057.     Else
  1058.     
  1059.         If (ptr.UsedRegisters = 1) And (lngRegCnt(0) > 1) Then
  1060.             ' one register which is a multiple
  1061.             If lngRegCnt(0) = 2 Or _
  1062.                lngRegCnt(0) = 3 Or _
  1063.                lngRegCnt(0) = 5 Or _
  1064.                lngRegCnt(0) = 9 Then
  1065.                
  1066.                 If lngRegCnt(0) = 2 Then
  1067.                     udtSIB.sscale = 0
  1068.                 Else
  1069.                     udtSIB.sscale = GetFirstSetBitIdx(lngRegCnt(0) - 1)
  1070.                 End If
  1071.                 
  1072.                 Select Case udeReg(0)
  1073.                     Case RegEAX:    udtSIB.index = 0:   udtSIB.base = 0
  1074.                     Case RegECX:    udtSIB.index = 1:   udtSIB.base = 1
  1075.                     Case RegEDX:    udtSIB.index = 2:   udtSIB.base = 2
  1076.                     Case RegEBX:    udtSIB.index = 3:   udtSIB.base = 3
  1077.                     Case RegESI:    udtSIB.index = 6:   udtSIB.base = 6
  1078.                     Case RegEDI:    udtSIB.index = 7:   udtSIB.base = 7
  1079.                     Case RegEBP:    udtSIB.index = 5:   udtSIB.base = 5
  1080.                                     rm.Mod = 1
  1081.                     Case Else:
  1082.                         SetError "invalid multiple of a register in SIB", udtInstr.Line, udtInstr.Section
  1083.                         Exit Function
  1084.                 End Select
  1085.                 
  1086.             ElseIf lngRegCnt(0) = 4 Or lngRegCnt(0) = 8 Then
  1087.                 ' if Mod of ModR/M byte would be > 0 here
  1088.                 ' EBP+sbyte/sdword would be encoded, too
  1089.                 rm.Mod = 0
  1090.                 udtSIB.base = 5
  1091.                 udtSIB.sscale = GetFirstSetBitIdx(lngRegCnt(0))
  1092.                 
  1093.                 Select Case udeReg(0)
  1094.                     Case RegEAX:    udtSIB.index = 0
  1095.                     Case RegECX:    udtSIB.index = 1
  1096.                     Case RegEDX:    udtSIB.index = 2
  1097.                     Case RegEBX:    udtSIB.index = 3
  1098.                     Case RegEBP:    udtSIB.index = 5
  1099.                     Case RegESI:    udtSIB.index = 6
  1100.                     Case RegEDI:    udtSIB.index = 7
  1101.                     Case Else:
  1102.                         SetError "invalid multiples of register in SIB", udtInstr.Line, udtInstr.Section
  1103.                         Exit Function
  1104.                 End Select
  1105.             
  1106.             Else
  1107.                 SetError "invalid multiples of register in SIB", udtInstr.Line, udtInstr.Section
  1108.                 Exit Function
  1109.                 
  1110.             End If
  1111.             
  1112.         ElseIf ptr.UsedRegisters = 2 Then
  1113.             ' 2 register in pointer
  1114.             
  1115.             Select Case lngRegCnt(lngScale)
  1116.                 Case 1, 2, 4, 8:
  1117.                 Case Else:
  1118.                     SetError "Possible multiples of scale register: 1, 2, 4, 8", udtInstr.Line, udtInstr.Section
  1119.                     Exit Function
  1120.             End Select
  1121.             
  1122.             If lngRegCnt(lngBase) <> 1 Then
  1123.                 SetError "Base register mustn't have a multiple", udtInstr.Line, udtInstr.Section
  1124.                 Exit Function
  1125.             End If
  1126.             
  1127.             ' ESP can only be encoded in the base, so it can't be the scale.
  1128.             ' Same thing for EBP, but the other way.
  1129.             If (lngRegCnt(lngScale) = 1) And (lngRegCnt(lngBase)) = 1 Then
  1130.                 If (udeReg(lngScale) = RegESP) Or (udeReg(lngBase) = RegEBP) Then
  1131.                     lngScale = lngBase
  1132.                     lngBase = 1 - lngScale
  1133.                 End If
  1134.             End If
  1135.             
  1136.             udtSIB.sscale = GetFirstSetBitIdx(lngRegCnt(lngScale))
  1137.             
  1138.             Select Case udeReg(lngScale)
  1139.                 Case RegEAX:    udtSIB.index = 0
  1140.                 Case RegECX:    udtSIB.index = 1
  1141.                 Case RegEDX:    udtSIB.index = 2
  1142.                 Case RegEBX:    udtSIB.index = 3
  1143.                 Case RegEBP:    udtSIB.index = 5
  1144.                 Case RegESI:    udtSIB.index = 6
  1145.                 Case RegEDI:    udtSIB.index = 7
  1146.                 Case Else:
  1147.                     SetError "invalid scale register", udtInstr.Line, udtInstr.Section
  1148.                     Exit Function
  1149.             End Select
  1150.             
  1151.             Select Case udeReg(lngBase)
  1152.                 Case RegEAX:    udtSIB.base = 0
  1153.                 Case RegECX:    udtSIB.base = 1
  1154.                 Case RegEDX:    udtSIB.base = 2
  1155.                 Case RegEBX:    udtSIB.base = 3
  1156.                 Case RegESP:    udtSIB.base = 4
  1157.                 Case RegEBP:    udtSIB.base = 5
  1158.                 Case RegESI:    udtSIB.base = 6
  1159.                 Case RegEDI:    udtSIB.base = 7
  1160.                 Case Else:
  1161.                     SetError "invalid base register", udtInstr.Line, udtInstr.Section
  1162.                     Exit Function
  1163.             End Select
  1164.         End If
  1165.     End If
  1166.     
  1167.     OutputByte (rm.Mod * &H40) Or (rm.reg * &H8) Or rm.rm
  1168.     OutputByte (udtSIB.sscale * &H40) Or (udtSIB.index * &H8) Or udtSIB.base
  1169.     If rm.DispSize <> BitsUnknown Then OutputBytes rm.Disp, rm.DispSize
  1170.     
  1171.     WriteSIB = True
  1172. End Function
  1173.  
  1174.  
  1175. Private Function ModRMRegNum(ByVal reg As ASMRegisters) As Long
  1176.     Select Case reg
  1177.         Case RegAL, RegAX, RegEAX:  ModRMRegNum = 0
  1178.         Case RegCL, RegCX, RegECX:  ModRMRegNum = 1
  1179.         Case RegDL, RegDX, RegEDX:  ModRMRegNum = 2
  1180.         Case RegBL, RegBX, RegEBX:  ModRMRegNum = 3
  1181.         Case RegAH, RegSP, RegESP:  ModRMRegNum = 4
  1182.         Case RegCH, RegBP, RegEBP:  ModRMRegNum = 5
  1183.         Case RegDH, RegSI, RegESI:  ModRMRegNum = 6
  1184.         Case RegBH, RegDI, RegEDI:  ModRMRegNum = 7
  1185.     End Select
  1186. End Function
  1187.  
  1188.  
  1189. Private Sub WriteModRM(rm As ModRM)
  1190.     OutputByte (rm.Mod * &H40) Or (rm.reg * &H8) Or rm.rm
  1191.     If rm.DispSize <> BitsUnknown Then OutputBytes rm.Disp, rm.DispSize
  1192. End Sub
  1193.  
  1194.  
  1195. Private Sub InstructionOutOpCode(udtInstr As ASMInstruction)
  1196.     Dim i As Long
  1197.     
  1198.     With Instructions(udtInstr.OpCodeIndex)
  1199.         For i = 0 To .OpCodeLen - 1
  1200.             OutputByte .OpCode(i)
  1201.         Next
  1202.     End With
  1203. End Sub
  1204.  
  1205.  
  1206. Private Sub InstructionOutPrefixes(udtInstr As ASMInstruction)
  1207.     With Instructions(udtInstr.OpCodeIndex)
  1208.         If (.Prefixes And PrefixFlgOperandSizeOverride) Then _
  1209.             OutputByte PREFIX_OPERAND_SIZE_OVERRIDE
  1210.         If (.Prefixes And PrefixFlgAddressSizeOverride) Then _
  1211.             OutputByte PREFIX_ADDRESS_SIZE_OVERRIDE
  1212.         If (.Prefixes And PrefixFlgBranchNotTaken) Then _
  1213.             OutputByte PREFIX_BRANCH_NOT_TAKEN
  1214.         If (.Prefixes And PrefixFlgBranchTaken) Then _
  1215.             OutputByte PREFIX_BRANCH_TAKEN
  1216.     End With
  1217.     
  1218.     With udtInstr
  1219.         If (.flags And PrefixFlgLock) Then _
  1220.             OutputByte PREFIX_LOCK
  1221.         If (.flags And PrefixFlgRep) Then _
  1222.             OutputByte PREFIX_REP
  1223.         If (.flags And PrefixFlgRepne) Then _
  1224.             OutputByte PREFIX_REPNE
  1225.     End With
  1226.     
  1227.     Select Case udtInstr.Segment
  1228.         Case SegCS: OutputByte PREFIX_SEGMENT_CS
  1229.         Case SegDS: OutputByte PREFIX_SEGMENT_DS
  1230.         Case SegES: OutputByte PREFIX_SEGMENT_ES
  1231.         Case SegFS: OutputByte PREFIX_SEGMENT_FS
  1232.         Case SegGS: OutputByte PREFIX_SEGMENT_GS
  1233.         Case SegSS: OutputByte PREFIX_SEGMENT_SS
  1234.     End Select
  1235. End Sub
  1236.  
  1237.  
  1238. Private Sub OutputMem(ByVal ptr As Long, ByVal Bytes As Long)
  1239.     If m_lngOutPos + Bytes > m_lngOutSize Then
  1240.         Err.Raise 123456, , "not enough space in output array"
  1241.     End If
  1242.     
  1243.     CopyMemory m_btOutput(m_lngOutPos), ByVal ptr, Bytes
  1244.     m_lngOutPos = m_lngOutPos + Bytes
  1245. End Sub
  1246.  
  1247.  
  1248. Private Sub OutputJumpTo(ByVal lngVal As Long)
  1249.     If (lngVal >= m_lngOutSize) Or (lngVal < 0) Then
  1250.         Err.Raise 123456, , "new position out of bounds"
  1251.     End If
  1252.     
  1253.     m_lngOutPos = lngVal
  1254. End Sub
  1255.  
  1256.  
  1257. Private Property Get OutputPosition() As Long
  1258.     OutputPosition = m_lngOutPos
  1259. End Property
  1260.  
  1261.  
  1262. Private Sub OutputBytes(ByVal Value As Long, ByVal size As ParamSize)
  1263.     Select Case size
  1264.         Case Bits8:     OutputByte Value
  1265.         Case Bits16:    OutputInteger Value
  1266.         Case Bits32:    OutputLong Value
  1267.         Case Else:      Err.Raise 123456, , "invalid size"
  1268.     End Select
  1269. End Sub
  1270.  
  1271.  
  1272. Private Sub OutputByte(ByVal Value As Long)
  1273.     If Value < 0 Then
  1274.         m_btOutput(m_lngOutPos) = CByte(Value + 256)    ' Signed Byte
  1275.     Else
  1276.         m_btOutput(m_lngOutPos) = CByte(Value)
  1277.     End If
  1278.     
  1279.     m_lngOutPos = m_lngOutPos + 1
  1280. End Sub
  1281.  
  1282.  
  1283. Private Sub OutputInteger(ByVal Value As Long)
  1284.     CopyMemory m_btOutput(m_lngOutPos), Value, 2
  1285.     m_lngOutPos = m_lngOutPos + 2
  1286. End Sub
  1287.  
  1288.  
  1289. Private Sub OutputLong(ByVal Value As Long)
  1290.     CopyMemory m_btOutput(m_lngOutPos), Value, 4
  1291.     m_lngOutPos = m_lngOutPos + 4
  1292. End Sub
  1293.  
  1294.  
  1295. Private Function ParsePointers() As Boolean
  1296.     Dim i   As Long
  1297.     Dim j   As Long
  1298.     
  1299.     For i = 0 To m_lngInstrCount - 1
  1300.         For j = 0 To m_udtInstrs(i).ArgCount - 1
  1301.             With m_udtInstrs(i).Args(j)
  1302.                 If .TType = ParamMem Then
  1303.                     m_lngCurToken = .Pointer.TokenIndex
  1304.                     If Not ParsePointer(.Pointer.ptr) Then Exit Function
  1305.                 End If
  1306.             End With
  1307.         Next
  1308.     Next
  1309.     
  1310.     ParsePointers = True
  1311. End Function
  1312.  
  1313.  
  1314. Private Function ParsePointer(ptr As Pointer) As Boolean
  1315.     Dim lngSgn      As Long
  1316.     Dim lngTms      As Long
  1317.     Dim lngVal      As Long
  1318.     Dim i           As Long
  1319.     Dim lngReg      As Long
  1320.     Dim blnReg      As Boolean
  1321.     
  1322.     If Not Match(TokenBracketLeft) Then
  1323.         SetError """["" expected", Token.Line, Token.Section
  1324.         Exit Function
  1325.     End If
  1326.     
  1327.     If Match(TokenOpAdd) Then
  1328.         lngSgn = 1
  1329.     ElseIf Match(TokenOpSub) Then
  1330.         lngSgn = -1
  1331.     Else
  1332.         lngSgn = 1
  1333.     End If
  1334.     
  1335.     Do
  1336.         lngTms = 1
  1337.         blnReg = False
  1338.         
  1339.         Do
  1340.             Select Case Token.TType
  1341.                 Case TokenRegister:
  1342.                     blnReg = True
  1343.                     lngReg = RegToIdx(RegStrToReg(Token.Content))
  1344.                     Match TokenRegister
  1345.                 Case TokenValue:
  1346.                     lngTms = lngTms * Token.Value
  1347.                     Match TokenValue
  1348.                 Case TokenSymbol:
  1349.                     lngTms = lngTms * m_udtLabels(GetLabelIndex(Token.Content)).Offset
  1350.                     Match TokenSymbol
  1351.             End Select
  1352.         Loop While Match(TokenOpMul)
  1353.         
  1354.         If blnReg Then
  1355.             ptr.Registers(lngReg) = ptr.Registers(lngReg) + lngSgn * lngTms
  1356.         Else
  1357.             ptr.Displacement = ptr.Displacement + lngSgn * lngTms
  1358.         End If
  1359.         
  1360.         If Match(TokenOpAdd) Then
  1361.             lngSgn = 1
  1362.         ElseIf Match(TokenOpSub) Then
  1363.             lngSgn = -1
  1364.         Else
  1365.             Exit Do
  1366.         End If
  1367.     Loop
  1368.     
  1369.     If Not Match(TokenBracketRight) Then
  1370.         SetError """]"" expected", Token.Line, Token.Section
  1371.     Else
  1372.         ParsePointer = True
  1373.     End If
  1374. End Function
  1375.  
  1376.  
  1377. Private Function GetInstructionSizes() As Boolean
  1378.     Dim i           As Long
  1379.     Dim j           As Long
  1380.     Dim k           As Long
  1381.     Dim size        As Long
  1382.     Dim lngImpSz    As Long
  1383.     Dim blnFoundI   As Boolean
  1384.  
  1385.     For i = 0 To m_lngInstrCount - 1                ' all instructions in the source
  1386.         If m_udtInstrs(i).Data.size <> BitsUnknown Then
  1387.             With m_udtInstrs(i)
  1388.                 .size = .Data.ValueCount * .Data.size \ 8
  1389.             End With
  1390.         Else
  1391.             blnFoundI = False
  1392.             
  1393.             For j = 0 To InstructionCount - 1       ' all known instructions
  1394.                 If StrComp(m_udtInstrs(i).Mnemonic, Instructions(j).Mnemonic, vbTextCompare) = 0 Then
  1395.                     blnFoundI = True
  1396.                     
  1397.                     If CompareInstrs(m_udtInstrs(i), Instructions(j)) Then
  1398.                         ' OpCode length + all used prefixes, ModR/M Byte
  1399.                         size = Instructions(j).OpCodeLen + _
  1400.                                BitCount(Instructions(j).Prefixes Or m_udtInstrs(i).flags) + _
  1401.                                Abs(m_udtInstrs(i).Segment <> SegUnknown) + _
  1402.                                Abs(Instructions(j).ModRM) + _
  1403.                                Abs(Instructions(j).Now3DByte > -1)
  1404.                         
  1405.                         ' immediates, displacement, SIB byte
  1406.                         If Instructions(j).ParamCount > 0 Then
  1407.                             For k = 0 To Instructions(j).ParamCount - 1
  1408.                                 With Instructions(j).Parameters(k)
  1409.                                     If Not .Forced Then
  1410.                                     
  1411.                                         Select Case .PType
  1412.                                         
  1413.                                             Case ParamImm, ParamRel:
  1414.                                                 size = size + .size \ 8 ' Imm
  1415.                                             
  1416.                                             Case ParamMem Or ParamReg, ParamMem:
  1417.                                                 If Not Instructions(j).ModRM And .PType = ParamMem Then
  1418.                                                     size = size + 4     ' Imm
  1419.                                                 Else
  1420.                                                     If m_udtInstrs(i).Args(k).Pointer.HasDisplacement Then
  1421.                                                         size = size + m_udtInstrs(i).Args(k).Pointer.DispSize \ 8
  1422.                                                     End If
  1423.                                                     
  1424.                                                     If m_udtInstrs(i).Args(k).Pointer.RegisterCount = 2 Or _
  1425.                                                        m_udtInstrs(i).Args(k).Pointer.RegisterMultiples Then
  1426.                                                         size = size + 1 ' SIB
  1427.                                                     End If
  1428.                                                 End If
  1429.                                                 
  1430.                                         End Select
  1431.                                         
  1432.                                     End If
  1433.                                 End With
  1434.                             Next
  1435.                         End If
  1436.                         
  1437.                         m_udtInstrs(i).OpCodeIndex = j
  1438.                         m_udtInstrs(i).size = size
  1439.                         Exit For
  1440.                     End If
  1441.                 End If
  1442.             Next
  1443.             
  1444.             If j = InstructionCount Then
  1445.                 If blnFoundI Then
  1446.                     SetError "invalid arguments", m_udtInstrs(i).Line, m_udtInstrs(i).Section
  1447.                 Else
  1448.                     SetError "unknown instruction: " & m_udtInstrs(i).Mnemonic, m_udtInstrs(i).Line, m_udtInstrs(i).Section
  1449.                 End If
  1450.                 
  1451.                 Exit Function
  1452.             End If
  1453.         End If
  1454.     Next
  1455.     
  1456.     FillInOffsets
  1457.     If m_blnWritePE Then
  1458.         m_lngPECodeSize = m_lngOutSize
  1459.         
  1460.         lngImpSz = GetNeededImportsSize()
  1461.         If lngImpSz = 0 Then
  1462.             m_lngOutSize = RoundToMinSize(GetPEHeaderSize()) + _
  1463.                            RoundToMinSize(m_lngPECodeSize) + _
  1464.                            RoundToMinSize(1)
  1465.         Else
  1466.             m_lngOutSize = RoundToMinSize(GetPEHeaderSize()) + _
  1467.                            RoundToMinSize(m_lngPECodeSize) + _
  1468.                            RoundToMinSize(lngImpSz)
  1469.         End If
  1470.         
  1471.         FillInIAT RoundToSectionSize(GetPEHeaderSize()) + _
  1472.                   RoundToSectionSize(m_lngPECodeSize)
  1473.     End If
  1474.  
  1475.     ReDim m_btOutput(m_lngOutSize - 1) As Byte
  1476.  
  1477.     GetInstructionSizes = True
  1478. End Function
  1479.  
  1480.  
  1481. ' calculate label- and instructionoffsets
  1482. Private Sub FillInOffsets()
  1483.     Dim i           As Long
  1484.     Dim j           As Long
  1485.     Dim lngPEOffset As Long
  1486.     
  1487.     If m_blnWritePE Then
  1488.         lngPEOffset = RoundToSectionSize(GetPEHeaderSize)
  1489.     End If
  1490.     
  1491.     For i = 0 To m_lngInstrCount - 1
  1492.         m_udtInstrs(i).Offset = m_lngOutSize + m_lngBaseAddress + lngPEOffset
  1493.         m_lngOutSize = m_lngOutSize + m_udtInstrs(i).size
  1494.  
  1495.         If j < m_lngLabelCount Then
  1496.             If m_udtLabels(j).Instruction = i Then
  1497.                 m_udtLabels(j).Offset = m_udtInstrs(i).Offset
  1498.                 j = j + 1
  1499.             End If
  1500.         End If
  1501.     Next
  1502.     
  1503.     If j < m_lngLabelCount Then
  1504.         With m_udtInstrs(m_lngInstrCount - 1)
  1505.             For j = j To m_lngLabelCount - 1
  1506.                 m_udtLabels(j).Offset = .Offset
  1507.             Next
  1508.         End With
  1509.     End If
  1510. End Sub
  1511.  
  1512.  
  1513. ' calculate jump addresses for imported functions
  1514. Private Sub FillInIAT(ByVal reladdr As Long)
  1515.     Dim i           As Long
  1516.     Dim j           As Long
  1517.     Dim k           As Long
  1518.     Dim libidx      As Long
  1519.     Dim fncidx      As Long
  1520.     
  1521.     For i = 0 To m_lngInstrCount - 1
  1522.         For j = 0 To m_udtInstrs(i).ArgCount - 1
  1523.             If (m_udtInstrs(i).Args(j).TType And ParamExt) Then
  1524.                 libidx = (m_udtInstrs(i).Args(j).SymbolIndex \ &H10000) And &HFFFF&
  1525.                 fncidx = m_udtInstrs(i).Args(j).SymbolIndex And &HFFFF&
  1526.                 m_udtInstrs(i).Args(j).Pointer.ptr.Displacement = GetExternRelOfFnc(libidx, fncidx, reladdr)
  1527.             End If
  1528.         Next
  1529.     Next
  1530. End Sub
  1531.  
  1532.  
  1533. ' compare parsed instruction with one of the instruction set
  1534. Private Function CompareInstrs( _
  1535.     src As ASMInstruction, _
  1536.     comp As Instruction _
  1537. ) As Boolean
  1538.  
  1539.     Dim i   As Long
  1540.     
  1541.     If src.ArgCount = comp.ParamCount Then
  1542.         For i = 0 To src.ArgCount - 1
  1543.             ' imm and rel should be treated equal
  1544.             With comp.Parameters(i)
  1545.                 If (.PType And src.Args(i).TType) = 0 Then
  1546.                     If Not (.PType = ParamImm And src.Args(i).TType = ParamRel) Then
  1547.                         If Not (.PType = ParamRel And src.Args(i).TType = ParamImm) Then
  1548.                             Exit Function
  1549.                         End If
  1550.                     End If
  1551.                 End If
  1552.             End With
  1553.             
  1554.             If comp.Parameters(i).Forced Then
  1555.                 Select Case comp.Parameters(i).PType
  1556.                     Case ParamReg:
  1557.                         If src.Args(i).Register <> comp.Parameters(i).Register Then
  1558.                             Exit Function
  1559.                         End If
  1560.                     Case ParamSTX:
  1561.                         If src.Args(i).FPURegister <> comp.Parameters(i).FPURegister Then
  1562.                             Exit Function
  1563.                         End If
  1564.                     Case ParamImm:
  1565.                         If src.Args(i).Value <> comp.Parameters(i).Value Then
  1566.                             Exit Function
  1567.                         End If
  1568.                 End Select
  1569.             Else
  1570.                 If comp.Parameters(i).PType = ParamMem Then
  1571.                     If Not comp.ModRM Then
  1572.                         If src.Args(i).Pointer.RegisterCount > 0 Then
  1573.                             ' instruction mustn't have registers in the pointer
  1574.                             ' because ModR/M isn't allowed for it
  1575.                             Exit Function
  1576.                         End If
  1577.                     End If
  1578.                 ElseIf (comp.Parameters(i).PType And ParamMM) Then
  1579.                     If IsDefinite(comp.Parameters(i).MMRegister) Then
  1580.                         If comp.Parameters(i).MMRegister <> src.Args(i).MMRegister Then
  1581.                             Exit Function
  1582.                         End If
  1583.                     Else
  1584.                         If src.Args(i).TType = ParamMem Then
  1585.                             If (comp.Parameters(i).PType And ParamMem) = 0 Then
  1586.                                 Exit Function
  1587.                             End If
  1588.                         Else
  1589.                             If (comp.Parameters(i).MMRegister And src.Args(i).MMRegister) = 0 Then
  1590.                                 Exit Function
  1591.                             End If
  1592.                         End If
  1593.                     End If
  1594.                 End If
  1595.             End If
  1596.             
  1597.             If (comp.Parameters(i).size And src.Args(i).size) = 0 Then
  1598.                 If comp.Parameters(i).size <> BitsUnknown Then
  1599.                     Exit Function
  1600.                 End If
  1601.             End If
  1602.         Next
  1603.         
  1604.         CompareInstrs = True
  1605.     End If
  1606. End Function
  1607.  
  1608.  
  1609. ' collect labels
  1610. Private Function FindLabels() As Boolean
  1611.     Dim i           As Long
  1612.     Dim lngInstrCnt As Long
  1613.     
  1614.     For i = 1 To m_lngTokenCount - 2
  1615.         If m_clsTokens(i).TType = TokenSymbol Then
  1616.             If m_clsTokens(i + 1).TType = TokenOpColon Then
  1617.                 If GetLabelIndex(m_clsTokens(i).Content) > -1 Then
  1618.                     SetError "ambigious names: " & m_clsTokens(i).Content, m_clsTokens(i).Line, m_clsTokens(i).Section
  1619.                     Exit Function
  1620.                 End If
  1621.                 AddLabel m_clsTokens(i).Content, lngInstrCnt
  1622.             End If
  1623.         ElseIf m_clsTokens(i).TType = TokenOperator Then
  1624.             lngInstrCnt = lngInstrCnt + 1
  1625.         ElseIf m_clsTokens(i).TType = TokenRawData Then
  1626.             lngInstrCnt = lngInstrCnt + 1
  1627.         End If
  1628.     Next
  1629.     
  1630.     FindLabels = True
  1631. End Function
  1632.  
  1633.  
  1634. ' skips labels because they're already collected
  1635. Private Function ParseInstructions() As Boolean
  1636.     If Not Match(TokenBeginOfInput) Then
  1637.         SetError "Unknown error occured while starting parsing", 0, ""
  1638.     Else
  1639.         Do While Token.TType <> TokenEndOfInput
  1640.             Select Case Token.TType
  1641.             
  1642.                 Case TokenExtern:
  1643.                     If m_blnWritePE Then
  1644.                         Match TokenExtern
  1645.                         If Not ParseExtern() Then Exit Do
  1646.                     Else
  1647.                         SetError "Externs only allowed in PE mode", Token.Line, Token.Section
  1648.                         Exit Function
  1649.                     End If
  1650.             
  1651.                 Case TokenSymbol:
  1652.                     Match TokenSymbol
  1653.                     If Not Match(TokenOpColon) Then
  1654.                         SetError """:"" expected after label ID", Token.Line, Token.Section
  1655.                         Exit Do
  1656.                     End If
  1657.                     
  1658.                 Case TokenOperator, TokenKeyword:
  1659.                     If Not ParseInstruction Then Exit Do
  1660.                     
  1661.                 Case TokenRawData:
  1662.                     If Not ParseRawData Then Exit Do
  1663.                     
  1664.                 Case Else:
  1665.                     If Token.TType <> TokenEndOfInstruction Then
  1666.                         SetError "Unexpected symbol: " & Token.Content, Token.Line, Token.Section
  1667.                         Exit Do
  1668.                     End If
  1669.                     
  1670.             End Select
  1671.             
  1672.             If Not Match(TokenEndOfInstruction) Then
  1673.                 SetError "Unexpected end", Token.Line, Token.Section
  1674.                 Exit Do
  1675.             Else
  1676.                 ParseInstructions = Token.TType = TokenEndOfInput
  1677.             End If
  1678.         Loop
  1679.     End If
  1680. End Function
  1681.  
  1682.  
  1683. Private Function AddExtern(ByVal lib As String, ByVal fnc As String) As Boolean
  1684.     Dim i   As Long
  1685.     Dim j   As Long
  1686.     
  1687.     AddExtern = True
  1688.     
  1689.     For i = 0 To m_lngExternCount - 1
  1690.         If StrComp(m_udtExtern(i).LibName, lib, vbTextCompare) = 0 Then
  1691.             For j = 0 To m_udtExtern(i).FunctionCount - 1
  1692.                 If StrComp(m_udtExtern(i).Functions(j), fnc, vbTextCompare) = 0 Then
  1693.                     Exit Function
  1694.                 End If
  1695.             Next
  1696.             
  1697.             With m_udtExtern(i)
  1698.                 ReDim Preserve .Functions(.FunctionCount) As String
  1699.                 .Functions(.FunctionCount) = fnc
  1700.                 .FunctionCount = .FunctionCount + 1
  1701.             End With
  1702.             Exit Function
  1703.         End If
  1704.     Next
  1705.     
  1706.     If i = m_lngExternCount Then
  1707.         ReDim Preserve m_udtExtern(m_lngExternCount) As ASMExtern
  1708.         
  1709.         With m_udtExtern(m_lngExternCount)
  1710.             .LibName = lib
  1711.             
  1712.             ReDim .Functions(0) As String
  1713.             .Functions(0) = fnc
  1714.             .FunctionCount = 1
  1715.         End With
  1716.         
  1717.         m_lngExternCount = m_lngExternCount + 1
  1718.     End If
  1719. End Function
  1720.  
  1721.  
  1722. Private Function ParseExtern() As Boolean
  1723.     Dim strLib  As String
  1724.     Dim strFnc  As String
  1725.         
  1726.     If Token.TType <> TokenString Then
  1727.         SetError "Expected: string identifier for library name", Token.Line, Token.Section
  1728.         Exit Function
  1729.     Else
  1730.         strLib = Token.Content
  1731.         Match TokenString
  1732.         
  1733.         If Not Match(TokenSeparator) Then
  1734.             SetError "Libraryname and functionname have to be seperated through a "",""", Token.Line, Token.Section
  1735.             Exit Function
  1736.         Else
  1737.             If Token.TType <> TokenSymbol Then
  1738.                 SetError "Expected: Name of the exporte function", Token.Line, Token.Section
  1739.                 Exit Function
  1740.             Else
  1741.                 strFnc = Token.Content
  1742.                 Match TokenSymbol
  1743.                 
  1744.                 If GetLabelIndex(strFnc) > -1 Then
  1745.                     SetError "Name not unique", Token.Line, Token.Section
  1746.                 Else
  1747.                     ParseExtern = AddExtern(strLib, strFnc)
  1748.                 End If
  1749.             End If
  1750.         End If
  1751.     End If
  1752. End Function
  1753.  
  1754.  
  1755. Private Function ParseRawData() As Boolean
  1756.     Dim udtInstr    As ASMInstruction
  1757.     Dim i           As Long
  1758.     Dim lngLen      As Long
  1759.     Dim lngTemp     As Long
  1760.     
  1761.     Select Case UCase$(Token.Content)
  1762.         Case "DB":  udtInstr.Data.size = Bits8
  1763.         Case "DW":  udtInstr.Data.size = Bits16
  1764.         Case "DD":  udtInstr.Data.size = Bits32
  1765.     End Select
  1766.     Match TokenRawData
  1767.     
  1768.     With udtInstr.Data
  1769.         Do
  1770.             Select Case Token.TType
  1771.                 Case TokenValue:
  1772.                     ReDim Preserve .Values(.ValueCount) As Long
  1773.                     .Values(.ValueCount) = Token.Value
  1774.                     .ValueCount = .ValueCount t - 1
  1775.             End If
  1776.             End If
  1777.                                  e _ame of SSSSSSS     tInstr.D        Xibidx, fncidx, reladdr)
  1778.        ea
  1779.         Do
  1780.       Ed If
  1781.       Xibidx,fTse "DW":  udtI               Case Else:
  1782.                         SetErrorse 2:
  1783.       Xibidx,fTse "DW":  udtI i = 0 To  udtI i = 0 ToD             uda    
  1784.  
  1785. Private Function ParlngInstrCnt + 1
  1786.         End If
  1787.     Next
  1788.       .Functions(.Fun
  1789.             udeReg(j) = IdxToReg(i)
  1790.             lngRegCnt(j) = ptr.Registers(i)
  1791.             j = j + 1
  1792.         End If
  1793.     Next
  1794.     
  1795.     ' determine the scale register (can have a multiple)
  1796.     If lngRegCnt(0) >= 1 And lngRegCnt(1) = 1 Then
  1797.         lnCnt    ttr.Us If lngRegCnt(0) >= 1         EArgsX  ReDim .Fun.Section
  1798.                 Else
  1799.          uda    
  1800.  
  1801. PenSs(j), fnc, vbTextCompare) = 0 Th( (.Prefixes And PrefixFlgBranc                Else
  1802.          uda    
  1803.  
  1804. PenSs(j), fnc, vbTextComparqn  ttr.Us8f
  1805.         E0
  1806.  
  1807. P    End Select
  1808.     Match Token
  1809.     
  1810.  Register Th          As Long
  1811.     Dim j               As L       If mUs8fhave to be seperated If oonits16
  1812.      A               Else
  1813.   Lib, strFn Sellse
  1814.   Lib,      
  1815.         m_lngExternCount = m_lH          Exit Function
  1816.              ernCount = m_ltCompare) = 0 Th( (.Prefixes  = meg(lngScale) = RegESP) Or (udeRegon
  1817. As ASMInstruction
  1818.     Eare) = 0 Th( (.Prefixeb _amuOfInput
  1819.             End If
  1820.         Loop
  1821.     End If
  1822. End Function
  1823.  
  1824.  
  1825. Private FunR  lngRegCnt(j) =kenSeparator) Then
  1826.             SetErroG        uda =
  1827.     Eare) qate Fut>Ss0t>Ss0t>Ss0t>Ss0t>Ss0t>gESP) Or (udeRegon
  1828. P    End Select
  1829.     Match Token
  1830.     
  1831.  Register Th          A     A             e _ame ofse
  1832.       eReg(j)iSetEsCkenOpColon Then
  1833.              j (.Prefixeb _amuOfInput
  1834.             End If
  1835.          ooniT    j (fAs L   End If
  1836.  register (can havv            ernCountount "r    Ifs0t>gESP) Or (udeR9 L         End If
  1837. uuctionCount Then
  1838.         <Pd SelecREFIX_SEs8ngExternCoun
  1839.                 If GetLabel           Ifc
  1840.                   If GetLabel    DArgs(j).SymbolInde  .Functions(.Funs
  1841.              ernCount = m1  .Functions(.Fuat            e _ame ofse
  1842.       eR1  
  1843.     If    Matc    End I     e GetLFuat            e _ame ofse
  1844.       eR1  
  1845.     If    Matc    End I     e GetLFuan
  1846.             With m_udtInstrs(i)a
  1847.         Do
  1848.                  ,                udtSIB.sscale = GetFirstSetBitIdx(loken.TTle _ame ofse
  1849.       eRElseIf Match(TokenOpSub) Then
  1850.            egon
  1851. As ASMX:    udtSIB.base = 2
  1852.           m j       eExtern((((((((((((((((((    egoncale = GetFirstS                  ' instructioFrnCountount "r    m j       eExtern((((((((((((((((((    "B FunstructioFrnCoe
  1853.                 strFnc = Token.Content
  1854.       )
  1855.             ln             udtSIB.sscale =nRR1  
  1856.     If    Matc  Content
  1857.       )
  1858.             ent = ptr.4d