News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

[help]Building a dll with Go tools.

Started by bobsobol, December 16, 2009, 05:09:02 AM

Previous topic - Next topic

bobsobol

Okay... I'm new here, so please go easy on me if I step on any toes. XD

I'm trying to get a build platform for DLL files using Go Tools, building on the MASM examples from Iczelion, but I always get the response from GoLink that the exported function is not exported, or builds a DLL with no functions. :(

Here is my build batch:-@Echo off
Echo %Time% - Building %1 >> Build.log
SetLocal
If %PROCESSOR_ARCHITECTURE%==AMD64 GoTo x64
  Set GoAsmDir=%ProgramFiles%\GoASM
  GoTo Process
:x64
  Set GoAsmDir=%ProgramFiles(x86)%\GoASM
:Process
"%GoAsmDir%\GoAsm" /c %1.asm >> Build.log

If Not Exist %1.rc GoTo NoRC
"%GoAsmDir%\GoRC" %1.rc  >> Build.log
"%GoAsmDir%\GoLink" %1.obj %1.res /DLL @%1.def >> Build.log
GoTo CleanUp
:NoRC
"%GoAsmDir%\GoLink" %1.obj /DLL @%1.def >> Build.log
:CleanUp
Del %1.obj
Del %1.res


My Test Assembly:-;--------------------------------------------------------------------------------------
;                           DLLSkeleton.asm
;-----------------+
; by: Iczelion    |
;--------------------------------------------------------------------------------------
;.386
;.model flat,stdcall
;option casemap:none


#include "include\windows.h"

CODE SECTION

START:
DllEntryPoint FRAME hInst, reason, reserved1
    mov  eax,TRUE
    ret
EndF

;---------------------------------------------------------------------------------------------------
;                                                This is a dummy function
; It does nothing. I put it here to show where you can insert  functions into
; a DLL.
;----------------------------------------------------------------------------------------------------
EXPORT TestFunction:
ret

It's def:-/Export TestFunction
And it's .rc :-#define VERINF1 1
VERINF1 VERSIONINFO
FILEVERSION 1,0,0,0
PRODUCTVERSION 1,0,0,0
FILEOS 0x00000004
FILETYPE 0x00000000
BEGIN
  BLOCK "StringFileInfo"
  BEGIN
    BLOCK "040904B0"
    BEGIN
      VALUE "CompanyName", "MyCompany\0"
      VALUE "FileVersion", "1.0.0\0"
      VALUE "FileDescription", "Test DLL\0"
      VALUE "LegalCopyright", "©ThisYear MyCompany\0"
      VALUE "ProductName", "Test DLL\0"
      VALUE "ProductVersion", "1.0.0\0"
    END
  END
  BLOCK "VarFileInfo"
  BEGIN
    VALUE "Translation", 0x0809, 0x04B0
  END
END


So please... tell me what I am doing wrong.

I can see that I need to define a FRAME when I pass parameters, but that's the next hurdle. XD Right now I just want the absolute basics of a DLL, with a single function that takes no parameters, and includes as little as possible.

I can find all sorts of information about calling DLLs from GoAssembler code... but how to write, and more importantly LINK one, is another story. And yet, I can think of many many reasons to write highly optimised DLLs in Assembler, (filters for AVISynth, PhotoShop or Premier, Game AIs etc) but no good reason to maintain an entire, medium to large scale application in Assembler.

TIA, bobsobol.

ecube

http://www.masm32.com/board/index.php?topic=11180.0

has dll example, on how to do 32bit and 64bit from same source and shows you how to build it. If you don't wanna look at that, can you post your errors from the above?

here's the build.bat for dll example in the link above

set INCLUDE=C:\GoAsm\include

\GoAsm\bin\GoAsm /x86 Dll.asm
\GoAsm\bin\GoLink /dll /entry DllEntry Dll.obj
pause


and for 64bit

set INCLUDE=C:\GoAsm\include

\GoAsm\bin\GoAsm /x64 Dll.asm
\GoAsm\bin\GoLink /dll /entry DllEntry /fo Dll64.dll Dll.obj
pause

bobsobol

Thanks for the response. %INCLUDE% is set for my local Asm dev environment.

I had tried the example in your unofficial GoAsm SDK before posting this topic... but even after correcting the include locations in it, it still fails to build, (using my build method, because you don't use a command file to link) and is far more complex than the simple skeleton I'm trying to start off with.

Which is to say, I don't really understand the code in it, with all the IFDEFs and such. I don't need x64 because the program(s) that will call any DLL my team make is/are closed source, discontinued x86 program(s) that we are currently maintaining (would you believe) in OllyDbg. I just want to find a more manageable way.

Background: Effectively, I'm an active member in a user group continuing support for a product who's author has given up on developing it... (at least in the manner we would like it to develop) But on a personal level I'm also interested in developing AVISynth or VirtualDub filters in Assembler... Those there is some hope for x64, but it's not practical YET. I'd rather not overload my brain with x64 just yet, when the last time I did any serious Intel Assembler was on DOS, where x86 was paged and 16-bit... at least on my Amstrad XT PC. ;) The rest of my Low Level programming has been done on Z80 and 68K microprocessors, with a smattering or ARM2... so I doubt I will struggle to make the change... just not right now. ;)

This is the build log produced by my batch:-16:56:09.41 - Building test

GoAsm.Exe Version 0.56.8 - Copyright Jeremy Gordon 2001/9 - JG@JGnet.co.uk
Output file: test.obj

GoRC.Exe Version 0.90.5 - Copyright Jeremy Gordon 1998/2009 - JG@JGnet.co.uk
Output file: test.res
Output file: test.obj format: win32

GoLink.Exe Version 0.26.14 - Copyright Jeremy Gordon 2002/9 - JG@JGnet.co.uk

Error!
The following exported symbol was not defined in the object file or files:-
TestFunction
Output file not made


As far as I can see, the symbol IS defined in the source... so I don't understand why (especially given that your example doesn't even use the command file) it should not be defined in the object file produced by GoAsm. :(

Oh, yea... if I don't link with the command file, it does produce a DLL, but that DLL has no exported functions. :s

As far as I can see... a 32bit only version of your example would be:-;------------------------------------------------------------------
;
;     Simple dll example, written by E^cube
;------------------------------------------------------
#DEFINE LINKFILES
#include "include\windows.h"
#include "include\tlhelp32.h"


DATA SECTION
uProcess PROCESSENTRY32
myprocess db 512 dup ?


CODE SECTION
EXPORT DllEntry FRAME hInstance, reason, reserved1
cmp D[reason],DLL_PROCESS_ATTACH
jne >@skip
;do initalizin here

@skip:
mov eax,1
ret
ENDF


;example exported function
EXPORT MsgBox FRAME iMsg
LOCAL pid:D
invoke GetCurrentProcessId
    mov [pid],eax
    invoke GetProcessName,[pid],addr myprocess
    invoke MessageBox,0,addr myprocess,"we're running in process",MB_OK
    invoke MessageBox,0,[iMsg],"Function called from 32bit Dll!",MB_OK
ret
ENDF

;32bit function that retrieves the process name from its pid
GetProcessName FRAME pid,oBuf
LOCAL isrunning:D
LOCAL isrunning2:D
LOCAL procesid:D
LOCAL hSnapshot:D
mov D[isrunning],1
mov D[isrunning],0
GetRunningAppss: 
invoke   CreateToolhelp32Snapshot,2h,0         
mov    [hSnapshot],eax

mov    D[uProcess.dwSize],sizeof PROCESSENTRY32

invoke   Process32First,eax,offset uProcess                   
jmp    GetRunningAppss_Chk

GetRunningAppss_Loop:
mov ecx,[pid]
cmp [uProcess.th32ProcessID],ecx
jne > keepcheckin
inc D[isrunning]
invoke lstrcpy,[oBuf],addr uProcess.szExeFile
jmp weregood
keepcheckin:
invoke   Process32Next,[hSnapshot],addr uProcess                     

GetRunningAppss_Chk:
test   eax,eax
jnz  <  GetRunningAppss_Loop               

weregood:
invoke   CloseHandle,[hSnapshot]                       
cmp D[isrunning],1
jne > @nope
xor eax,eax
ret
@nope:
mov eax,-1
ret
ENDF

So... is it just that I don't #DEFINE LINKFILES? A test including that define seems to make no difference.

If I make a .def command file for this source (your example cut down to 32-bit only) I actually get each function exported twice in the final DLL, and a warning that there is no (optional) entry point for the DLL.

This is because you didn't define the "START:" label, if I'm not mistaken.

On the other hand, I'm still using the "DllEntryPoint" export that Iczlion used in MASM, where you just define "DllEntry"... is that connected?

Yuri


GoAsm.Exe Version 0.56.8 - Copyright Jeremy Gordon 2001/9 - JG@JGnet.co.uk
Output file: test.obj

GoRC.Exe Version 0.90.5 - Copyright Jeremy Gordon 1998/2009 - JG@JGnet.co.uk
Output file: test.res
Output file: test.obj format: win32


GoRC produces two files, among them another test.obj, which apparently overwrites the first test.obj produced by GoAsm. So, try changing the corresponding command to:

"%GoAsmDir%\GoRC" /r %1.rc


The /r option forces GoRC to build only .res files.

ecube

#DEFINE LINKFILES
is a switch in donkey's header files (look at windows.h, has comments explaining the switches at the top) that includes the necessary DLL files GoASM searches for, to find the exported functions you're using(importing) within your dll, exe etc...C,MASM etc require you to specify .lib's, GoASM is smarter than that.

There is no Start: because DllEntry is the entrypoint for the Dll, you can Name it whatever you like just edit the

"/entry DllEntry" in the build.bat to the name if you change it. It's a switch sent to the linker.

bobsobol

Cracker Yuri! :U

That is exactly the solution.  :bg  :clap:

Thank you so much... I've been fighting that for the last 5 days going round in circles.

Had to be something simple didn't it, these things always are.

Thank you, thank you, thank you all. :cheekygreen:

---EDIT---
Yes... Build.bat should be a general, it is called by a Make.bat for all the plugin dlls for the entire project... so I wanted the .asm to define the entry point, not build.bat. As I say, it's optional, and only a warning. Your intent is different from mine, I just wanted to explain that that warning does NOT confuse me. ;)

The #DEFINE LINKFILE did, so thanks for the explain. I have tried several assemblers, and have chosen Go, exactly because it "is smarter than that". HLA is pretty smart too, but the people I'm working with are used to seeing x86 mnemonics in Olly, stuff like "Invoke" is going to be new for them, let alone mixed High and Low level stuff. ROSAsm has a very advanced IDE, but we aren't changing the UI of the program, just the internal logic... so it's advanced in exactly the wrong places, for us.

So I now know that I can define the exports in the .def (command file) for GoLink or in the Assembly listing to GoAsm as EXPORT or EXPORTS instructions... It doesn't matter which I do, but I shouldn't do both, or I fill the Export table up with doubles of each entry.

Once again, thanks for all the help.