Author Topic: Tools for building 64-bit import libraries  (Read 1066 times)

nidud

  • Member
  • *****
  • Posts: 2013
    • https://github.com/nidud/asmc
Tools for building 64-bit import libraries
« on: May 13, 2020, 10:05:32 PM »
Tools included:

    DLL32.EXE - Test if 32-bit version is installed
    DLL64.EXE - Test if 64-bit version is installed
    DEF64.EXE - Creates a .DEF file for LIB.EXE
    IMP64.EXE - Creates a .LIB file from a DLL
    LIBW.EXE  - Library manager used by IMP64

Example:

    DLL32 user32

C:\Windows\syswow64\user32.dll:
 Machine:       I386
 ImageBase:     74D60000

    DLL64 user32

C:\Windows\system32\user32.dll:
 Machine:               AMD64
 ImageBase:             0000000077320000
 Large address aware:   Yes
 ASLR:                  Yes     /DYNAMICBASE
 ASLR^2:                No      /HIGHENTROPYVA
 DEP:                   Yes     /NXCOMPAT
 TS Aware:              No      /GS

Build the library user32.lib:

    IMP64 user32

Create user32.def:

    DEF64 user32

felipe

  • Member
  • *****
  • Posts: 1360
  • At least we are not alone...
Re: Tools for building 64-bit import libraries
« Reply #1 on: May 14, 2020, 12:29:42 AM »
Wow this looks like a really promise program  :thup:, i have to try it. Thanks a lot nidud. I will give feedback on it later.  :thumbsup:
No remarkable words at all...

TimoVJL

  • Member
  • ****
  • Posts: 586
Re: Tools for building 64-bit import libraries
« Reply #2 on: May 14, 2020, 01:09:38 AM »
polib.exe is for that.
May the source be with you

nidud

  • Member
  • *****
  • Posts: 2013
    • https://github.com/nidud/asmc
Re: Tools for building 64-bit import libraries
« Reply #3 on: May 14, 2020, 01:40:30 AM »
polib.exe is for that.

I don't think POLIB is capable of producing .DEF files from system DLL's but I could be wrong. I will assume POLIB is a LIB clone and as most library managers capable of producing libraries from definition files.

Vortex

  • Member
  • *****
  • Posts: 2457
Re: Tools for building 64-bit import libraries
« Reply #4 on: May 14, 2020, 02:33:46 AM »
Hi nidud,

Thanks for your new tools.

Polib can create module definition files from DLLs :

Code: [Select]
C:\PellesC\Bin>polib.exe /MAKEDEF:user32.def /MACHINE:x86 C:\Windows\System32\user32.dll

C:\PellesC\Bin>type user32.def | findstr "MessageBox"
"MessageBoxA" ; USER32.dll
"MessageBoxExA" ; USER32.dll
"MessageBoxExW" ; USER32.dll
"MessageBoxIndirectA" ; USER32.dll
"MessageBoxIndirectW" ; USER32.dll
"MessageBoxTimeoutA" ; USER32.dll
"MessageBoxTimeoutW" ; USER32.dll
"MessageBoxW" ; USER32.dll
"SoftModalMessageBox" ; USER32.dll

hutch--

  • Administrator
  • Member
  • ******
  • Posts: 7800
  • Mnemonic Driven API Grinder
    • The MASM32 SDK
Re: Tools for building 64-bit import libraries
« Reply #5 on: May 14, 2020, 02:47:07 AM »
It does not matter if more tools can do useful things, I use Pelle's polib to do a number of things but having extra tools is a good idea.
hutch at movsd dot com
http://www.masm32.com    :biggrin:  :skrewy:

nidud

  • Member
  • *****
  • Posts: 2013
    • https://github.com/nidud/asmc
Re: Tools for building 64-bit import libraries
« Reply #6 on: May 14, 2020, 03:09:26 AM »

polib /makedef:msvcrt.def /machine:x64 C:\windows\system32\msvcrt.dll
POLIB: fatal error: Corrupt library: 'C:\windows\system32\msvcrt.dll'.

polib /makedef:msvcrt.def /machine:x86 C:\windows\system32\msvcrt.dll
POLIB: fatal error: Corrupt library: 'C:\windows\system32\msvcrt.dll'.

polib /makedef:msvcrt.def /machine:x86 C:\windows\syswow64\msvcrt.dll
POLIB: fatal error: Corrupt library: 'C:\windows\syswow64\msvcrt.dll'.

The version tested seems to be 32-bit so it will only be able (if it works) to load the 32-bit version of the DLL which differ from 64-bit version. You need a 64-bit EXE to load a 64-bit DLL.

Vortex

  • Member
  • *****
  • Posts: 2457
Re: Tools for building 64-bit import libraries
« Reply #7 on: May 14, 2020, 03:30:23 AM »
Hi nidud,

I didn't get any error messages on Windows 10 64-bit :

Code: [Select]
C:\PellesC\Bin>ver

Microsoft Windows [Version 10.0.18363.778]

C:\PellesC\Bin>polib.exe
Pelles Library Manager, Version 9.00.0
Copyright (c) Pelle Orinius 1997-2018

Syntax:
POLIB [ { option | file | @commandfile } ... ]

Code: [Select]
C:\PellesC\Bin>polib /makedef:msvcrt.def /machine:x64 C:\windows\system32\msvcrt.dll

C:\PellesC\Bin>ren msvcrt.def msvcrt64.def

C:\PellesC\Bin>polib /makedef:msvcrt.def /machine:x86 C:\windows\system32\msvcrt.dll

C:\PellesC\Bin>del msvcrt.def

C:\PellesC\Bin>polib /makedef:msvcrt32.def /machine:x86 C:\windows\syswow64\msvcrt.dll

Vortex

  • Member
  • *****
  • Posts: 2457
Re: Tools for building 64-bit import libraries
« Reply #8 on: May 14, 2020, 03:36:06 AM »
Hi nidud,

Quote
You need a 64-bit EXE to load a 64-bit DLL.

That's true but one can code a 32-bit tool loading 64-bit DLLs as data files. The purpose would be to read the export section according to the MS PE specification and create DEF files.

nidud

  • Member
  • *****
  • Posts: 2013
    • https://github.com/nidud/asmc
Re: Tools for building 64-bit import libraries
« Reply #9 on: May 14, 2020, 04:42:09 AM »
Code: [Select]
C:\PellesC\Bin>ver

Microsoft Windows [Version 10.0.18363.778]

C:\PellesC\Bin>polib.exe
Pelles Library Manager, Version 9.00.0
Copyright (c) Pelle Orinius 1997-2018

Microsoft Windows [Versjon 6.1.7601]
D:\PellesC\bin>polib
Pelles Library Manager, Version 8.00.0
Copyright (c) Pelle Orinius 1997-2015

Could be a version problem.

nidud

  • Member
  • *****
  • Posts: 2013
    • https://github.com/nidud/asmc
Re: Tools for building 64-bit import libraries
« Reply #10 on: May 14, 2020, 06:06:09 AM »
Upgraded PellesC to version 9.00 and yes, it works  :thumbsup:

That's true but one can code a 32-bit tool loading 64-bit DLLs as data files. The purpose would be to read the export section according to the MS PE specification and create DEF files.

That seems to be how this works so you need to know the bitness of the DLL before you use it. I find it more convenient to use LoadLibrary() to get the correct version of the DLL. This also simplify the install process where you don't have to relay on specific paths and environment variables.

In the test you used the second one will then fail (/machine:x86 C:\windows\system32\msvcrt.dll) given it will use the content of the 64-bit DLL for a 32-bit library.

The content of the 64-bit DEF file contains around 1300 entries:

LIBRARY "msvcrt.dll"
EXPORTS
"??0__non_rtti_object@@QEAA@AEBV0@@Z" ; msvcrt.dll
"??0__non_rtti_object@@QEAA@PEBD@Z" ; msvcrt.dll
"??0bad_cast@@AAE@PBQBD@Z" ; msvcrt.dll
...
"?what@exception@@UEBAPEBDXZ" ; msvcrt.dll
"_CrtCheckMemory" ; msvcrt.dll
"_CrtDbgBreak" ; msvcrt.dll
"_CrtDbgReport" ; msvcrt.dll
"_CrtDbgReportV" ; msvcrt.dll
"_CrtDbgReportW" ; msvcrt.dll

The content of the 32-bit DEF file contains around 1400 entries:

LIBRARY "msvcrt.dll"
EXPORTS
"$I10_OUTPUT" ; msvcrt.dll
"??0__non_rtti_object@@QAE@ABV0@@Z" ; msvcrt.dll
"??0__non_rtti_object@@QAE@PBD@Z" ; msvcrt.dll
"??0bad_cast@@AAE@PBQBD@Z" ; msvcrt.dll
...
"?what@exception@@UBEPBDXZ" ; msvcrt.dll
"_CIacos" ; msvcrt.dll
"_CIasin" ; msvcrt.dll
"_CIatan" ; msvcrt.dll
"_CIatan2" ; msvcrt.dll

The MASM64 SDK uses POLIB version 8.00 and predefined DEF files. The content of the 64-bit msvcrt.def file contains around 770 entries:

LIBRARY "msvcrt.dll"
EXPORTS
"$I10_OUTPUT" ; msvcrt.dll
"??0__non_rtti_object@@QEAA@AEBV0@@Z" ; msvcrt.dll
"??0__non_rtti_object@@QEAA@PEBD@Z" ; msvcrt.dll
"??0bad_cast@@AEAA@PEBQEBD@Z" ; msvcrt.dll
...
"?what@exception@@UEBAPEBDXZ" ; msvcrt.dll
"_CxxThrowException" ; msvcrt.dll
"_Getdays" ; msvcrt.dll
"_Getmonths" ; msvcrt.dll
"_Gettnames" ; msvcrt.dll

The DEF64 tool probably needs to add an extension:

LIBRARY msvcrt
EXPORTS

Mikl__

  • Member
  • *****
  • Posts: 1044
Re: Tools for building 64-bit import libraries
« Reply #11 on: May 14, 2020, 04:15:51 PM »
Creating inc- and lib-files from system dlls
inc-files - are text files containing a description of the data structures and Windows constants, and macros.
inc-files are formed by the programmer as the means of the operating system used by him expand. Similar to the header h/hpp- files used when programming in C/C++, sometimes you can generate inc-files from h-files using the h2inc.exe utility (it can be found in old MASM packages).
Purpose lib-files - providing link.exe with information about external links to WinAPI functions inside system dll files. A lib file is an archive that stores a set of "external character" mappings - a link to an object (COFF or PE) file. This "symbol" at the linking stage is either added to the executable image (in the case of COFF, from a precompiled object file), or is written in the import table (in the case of PE). That is, some external links are translated into your exe or dll.
link.exe processes the standard COFF libraries and COFF import libraries, which have a .lib extension. Standard libraries contain objects and are created using the lib.exe utility. Import libraries contain information about export to other programs and are created either by the link.exe compiler when building the program containing the export, or by the lib.exe utility.
To get the contents of the system dll-file I use the following bat-file
Code: [Select]
@ echo off
:: erase from the screen
cls
:: set the path to the masm64 directory
set masm64_path=\masm64\
:: name of the "prepared dll", start with user32
set FileName=user32
if exist %FileName%.inc del %FileName%.inc
if exist %FileName%.def del %FileName%.def
:: process user32.dll and get user32.txt file
%masm64_path%bin\dumpbin.exe /EXPORTS %windir%\System32\% FileName%.dll /OUT:%FileName%.txt
@echo EXPORTS >> %FileName%.def
for /f "skip=16 tokens=1-4" %%a in (%FileName%.txt ) do ( if "%%a"=="Summary" goto : exit
if "%%d"=="" ( @echo extern __imp_%FileName%_ordinal%%a:qword >> %FileName%.inc
@echo %FileName%_ordinal%%a TEXTEQU ^<__imp_%FileName%_ordinal %%a ^> >> %FileName%.inc
@echo %FileName%_ordinal%%a=ordinal%%a @ %%a NONAME >> %FileName%.def
) else ( if not "%%d"=="(forwarded" ( @echo extern __imp_%%d:qword >> %FileName%.inc
@echo %%d TEXTEQU ^<__imp_%%d ^> >> %FileName%.inc
@echo %%d=__imp_%%d >> %FileName%.def )))
: exit
%masm64_path%bin\link -lib /DEF: %FileName%.def /OUT: %FileName%.lib /MACHINE:X64
Parsing a bat-file
  • preset bat file
Code: [Select]
:: erase from the screen
cls
:: set the path to the masm64 directory
set masm64_path=\masm64\
:: name of the "prepared dll", start with user32
set FileName=user32
:: process user32.dll and get user32.txt file
%masm64_path%bin\dumpbin.exe /EXPORTS %windir%\System32\%FileName%.dll /OUT:%FileName%.txt
  • user32.txt contents
Code: [Select]
Dump of file C:\Windows\System32\user32.dll
File Type: DLL
  Section contains the following exports for USER32.dll
    00000000 characteristics
    4CE799CD time date stamp Sat Nov 20 17:50:05 2010
        0.00 version
        1500 ordinal base
        1003 number of functions
         830 number of names
    ordinal hint RVA name
       1502 0 000083C0 ActivateKeyboardLayout
       1503 1 0002AD40 AddClipboardFormatListener
       1504 2 000235B8 AdjustWindowRect
       1505 3 00017CE4 AdjustWindowRectEx
 ....
       2341 33C 0007B430 wvsprintfA
       2342 33D 00020BFC wvsprintfW
       1500 0002B260 [NONAME]
       1501 0002AE80 [NONAME]
....
  Summary
        2000 .data
        A000 .pdata
       10000 .rdata
        1000 .reloc
       5B000 .rsrc
       81000 .text
  • after watching user32.txt seen that from user32.dll imported 846 functions, including 826 functions imported by name, 16 - on the ordinals and the functions DefDlgProcA, DefDlgProcW, DefWindowProcA, DefWindowProcW ported in user32.dll from the system library NTDLL.dll
Code: [Select]
Dump of file C:\Windows\System32\user32.dll
File Type: DLL
  Section contains the following exports for USER32.dll
    00000000 characteristics
    4CE799CD time date stamp Sat Nov 20 17:50:05 2010
        0.00 version
        1500 ordinal base
        1003 number of functions
         830 number of names
    ordinal hint RVA name
       1502 0 000083C0 ActivateKeyboardLayout <--- useful information starts here
  • if the user32.inc, user32.def, user32.lib files remaining from the previous processing of the dll-files already exist in the directory before starting processing, we delete them.
Code: [Select]
if exist %FileName%.inc del %FileName%.inc
if exist %FileName%.def del %FileName%.def
create user32.def file , which should begin with the line "EXPORTS"
Code: [Select]
@echo EXPORTS >> %FileName%.def
  • useful information starts in user32.txt with line 16, so skip = 16 means - skip the first 16 lines in user32.txt
  • when line-by-line parsing the user32.txt file, we use the first four words in the line to which we will assign the names %%a, %%b, %%c, %%d
Code: [Select]
for /f "skip=16 tokens=1-4" %%a in (%FileName%.txt ) doif the first parameter is "Summary" - then all the functions included in the dll are processed, we stop processing, exit the user32.txt file and go to the label :exit
Code: [Select]
if "%%a"=="Summary" goto :exitif the fourth parameter in the user32.txt file is empty - we have before us import by ordinals
Code: [Select]
       %%a         %%b      %%c          %%d
       1500      0002B260 [NONAME]             
save the first word (the ordinal of the WinAPI function) in the user32.txt line in the variable %%a, frame it and put it in two new lines in the user32.inc file
Code: [Select]
extern __imp_user32_ordinal1500: qword
user32_ordinal1500 TEXTEQU <__imp_user32_ordinal1500>
and user32.def
Code: [Select]
user32_ordinal1500 = ordinal1500 @ 1500 NONAMEif the fourth parameter is non-empty - we have before us import by function names
in the next line of user32.txt
Code: [Select]
%%a   %%b  %%c      %%d
1502 0 000083C0 ActivateKeyboardLayout
the fourth word in the line (the name of the WinAPI function), save in the variable %%d, create two new lines in the user32.inc file , precede %%d "extern __imp_" end the line ":qword", add "TEXTEQU", "__imp_ ", we escape the control characters "<" and ">" (^<__ imp_%%d ^> so that the bat-file perceives them as ordinary characters.
Code: [Select]
extern __imp_ActivateKeyboardLayout:qword
ActivateKeyboardLayout TEXTEQU <__imp_ActivateKeyboardLayout>
and user32.def
Code: [Select]
ActivateKeyboardLayout = __ imp_ActivateKeyboardLayout
  • if the fourth parameter is "(forwarded", then the WinAPI function is taken from another dll and we skip such a line.
Code: [Select]
%%a    %%b         %%c           %%d
1657       94      DefDlgProcA    (forwarded to NTDLL.NtdllDialogWndProc_A )
  • from the contents of user32.def and user32.inc files, create user32.lib file
Code: [Select]
: exit
%masm64_path%bin\link -lib /DEF: %FileName%.def /OUT: %FileName%.lib/MACHINE: X64
the same result can be achieved by string
Code: [Select]
%masm64_path%bin\lib /DEF: %FileName%.def /OUT: %FileName%.lib /MACHINE:X64
  • we transfer the user32.inc file to the masm64\include directory, and the user32.lib file to the masm64\lib directory
  • remove software junk
Code: [Select]
if exist %FileName%.def del %FileName%.def
if exist %FileName%.exp del %FileName%.exp
if exist %FileName%.txt del %FileName%.txt
« Last Edit: May 14, 2020, 08:04:01 PM by Mikl__ »

nidud

  • Member
  • *****
  • Posts: 2013
    • https://github.com/nidud/asmc
Re: Tools for building 64-bit import libraries
« Reply #12 on: May 14, 2020, 11:39:10 PM »
 :biggrin:

Note that these tools have been available in the Asmc package from the first release, so here's a modified version of SYSDLL that creates LIB and INC files directly. The sample uses LIB, LINK, and ML64 to produce a simple Hello World.

; sysdll -inc -lib msvcrt
; ml64 test.asm -link -entry:main -subsystem:console

include msvcrt.inc

    .data
    string db "Hello Wolrd!",10,0
    .code

main proc
    lea rcx,string
    call printf
    xor ecx,ecx
    call exit
main endp

    end

nidud

  • Member
  • *****
  • Posts: 2013
    • https://github.com/nidud/asmc
Re: Tools for building 64-bit import libraries
« Reply #13 on: May 15, 2020, 12:03:09 AM »
The sysdll tool also allows wildcard and an optional target path. To create header files for all DLL files (not recommended: there's a lot of them) in the system32 directory to inc:

sysdll -inc *.dll inc

Source:
Code: [Select]
; build: asmc64 -I\Asmc\include -pe sysdll.asm
include io.inc
include direct.inc
include string.inc
include stdio.inc
include stdlib.inc
include winbase.inc
include tchar.inc

    .code

exit_usage proc
    printf(
        "Usage: SYSDLL <options> <name> [<out_path]\n"
        "\n"
        " /def - create .def files\n"
        " /lib - create .lib files\n"
        " /inc - create .inc files\n"
    )
    exit(0)
exit_usage endp

BuildInc proc uses rsi rdi rbx dll_name:LPSTR, out_path:LPSTR

  local fp:ptr FILE
  local dst[_MAX_PATH]:char_t
  local dll[_MAX_PATH]:char_t

    lea rdi,dll
    .if strrchr(strcpy(rdi, rcx), '.')
        mov byte ptr [rax],0
    .endif
    sprintf(&dst, "%s\\%s.inc", out_path, rdi)
    strcat(rdi, ".dll")

    .if LoadLibrary(rdi)

        mov rbx,rax

        .if fopen(&dst, "wt")

            mov fp,rax
            mov byte ptr [strrchr(rdi, '.')],0
            fprintf(fp,
                "ifdef __ASMC__\n"
                ".pragma comment(lib, %s)\n"
                "else\n"
                "includelib %s.lib\n"
                "endif\n", rdi, rdi)

            mov eax,[rbx].IMAGE_DOS_HEADER.e_lfanew
            mov eax,[rbx+rax].IMAGE_NT_HEADERS.OptionalHeader.DataDirectory.VirtualAddress
            mov edi,[rbx+rax].IMAGE_EXPORT_DIRECTORY.NumberOfNames
            mov esi,[rbx+rax].IMAGE_EXPORT_DIRECTORY.AddressOfNames

            .if esi && eax

                add rsi,rbx
                .while edi

                    lodsd
                    lea r8,[rax+rbx]

                    .if byte ptr [r8] != '?'

                        mov eax,[r8]
                        .if eax != "vid" && eax != "sbaf"

                            fprintf(fp, "%s proto :vararg\n", r8)
                        .endif
                    .endif
                    dec edi
                .endw
            .endif
            fclose(fp)
        .else
            perror(&dst)
        .endif
        FreeLibrary(rbx)
        xor eax,eax
    .else
        perror(rdi)
        mov eax,1
    .endif
    ret

BuildInc endp

BuildDef proc uses rsi rdi rbx dll_name:LPSTR, out_path:LPSTR

  local fp:ptr FILE
  local def[_MAX_PATH]:char_t
  local dll[_MAX_PATH]:char_t

    lea rdi,dll
    .if strrchr(strcpy(rdi, rcx), '.')
        mov byte ptr [rax],0
    .endif
    sprintf(&def, "%s\\%s.def", out_path, rdi)
    strcat(rdi, ".dll")

    .if LoadLibrary(rdi)

        mov rbx,rax

        .if fopen(&def, "wt")

            mov fp,rax
            fprintf(rax, "LIBRARY %s\nEXPORTS\n", rdi)

            mov eax,[rbx].IMAGE_DOS_HEADER.e_lfanew
            mov eax,[rbx+rax].IMAGE_NT_HEADERS.OptionalHeader.DataDirectory.VirtualAddress
            mov edi,[rbx+rax].IMAGE_EXPORT_DIRECTORY.NumberOfNames
            mov esi,[rbx+rax].IMAGE_EXPORT_DIRECTORY.AddressOfNames

            .if esi && eax

                add rsi,rbx

                .while edi

                    lodsd
                    lea r8,[rax+rbx]
                    ;.if byte ptr [r8] != '?'
                        fprintf(fp, "%s\n", r8)
                    ;.endif
                    dec edi
                .endw
            .endif
            fclose(fp)
        .else
            perror(&def)
        .endif
        FreeLibrary(rbx)
        xor eax,eax
    .else
        perror(rdi)
        mov eax,1
    .endif
    ret

BuildDef endp

BuildLib proc uses rsi rdi dll_name:LPSTR, out_path:LPSTR

  local dll[_MAX_PATH]:char_t
  local buf[_MAX_PATH]:char_t

    .return .if BuildDef(rcx, ".")

    lea rdi,buf
    lea rsi,dll
    .if strrchr(strcpy(rsi, dll_name), '.')
        mov byte ptr [rax],0
    .endif

    sprintf(rdi, "lib /def:%s.def /out:%s\\%s.lib /machine:x64", rsi, out_path, rsi)
    system(rdi)
    strcat(rsi, ".def")
    remove(rsi)
    xor eax,eax
    ret

BuildLib endp

main proc argc:SINT, argv:ptr

  local wild[128]:sbyte
  local path[_MAX_PATH]:sbyte
  local out_path:LPSTR
  local ff:_finddata_t
  local option_def:byte
  local option_lib:byte
  local option_inc:byte

    xor eax,eax
    mov option_def,al
    mov option_lib,al
    mov option_inc,al
    mov wild,al
    lea rax,@CStr(".")
    mov out_path,rax

    lea edi,[ecx-1] ; argc
    lea rsi,[rdx+8] ; argv

    .while edi

        lodsq
        mov rbx,rax
        mov eax,[rbx]

        .switch al
          .case '/'
          .case '-'
            .if ah == 'd'
                inc option_def
                .endc
            .elseif ah == 'l'
                inc option_lib
                .endc
            .elseif ah == 'i'
                inc option_inc
                .endc
            .endif
            exit_usage()
          .default
            .if wild
                mov out_path,rbx
            .else
                .if strrchr(strcpy(&wild, rbx), '.')
                    mov byte ptr [rax],0
                .endif
            .endif
            .endc
        .endsw
        dec edi
    .endw

    .if !option_inc && !option_def && !option_lib
        exit_usage()
    .endif
    .if !wild
        mov word ptr wild,'*'
    .endif
    mov rcx,out_path
    .if word ptr [rcx] != '.'
        _mkdir(rcx)
    .endif

    .if getenv("windir")

        lea rbx,ff.name
        lea rdi,path
        sprintf(rdi, "%s\\system32\\%s.dll", rax, &wild)

        .ifd _findfirst(rdi, &ff) != -1
            mov rsi,rax
            .repeat
                .if !( ff.attrib & _A_SUBDIR )
                    .if option_inc
                        BuildInc(rbx, out_path)
                    .endif
                    .if option_def
                        BuildDef(rbx, out_path)
                    .endif
                    .if option_lib
                        BuildLib(rbx, out_path)
                    .endif
                .endif
            .until _findnext(rsi, &ff)
            _findclose(rsi)
        .endif
    .endif
    xor eax,eax
    ret

main endp

    end _tstart