News:

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

Linking a MS VC++ 6.0 built library to MASM32 project

Started by mkey, January 04, 2012, 01:20:59 PM

Previous topic - Next topic

mkey

First of all, thanks for your time investment into reading this garble of mine.

I took the time to consider the right section for this topic, this may or may not be the right place. I also took the time to search instead of taking time to sleep and what is dawning on me is - there are some major misconceptions regarding this matter in my head. I'm not a newbie at MASM, been at it for years now, but I can be a full fledged idiot at times.

Anyway, like the topic title says, I'm trying to use a library written in c (it's the opensource cyassl project) compiled with VC++ 6.0 in my MASM32 project. Basically, this proggie of mine would like to connect via sockets wrapped in ssl to gmail pop3 servers and establish communication.

So, I took the .c and .h files from the cyassl package and placed them into a newly created VC++ 6.0 (library) project. Went into project properties and changed the calling convention to stdcall, the same what is used in my MASM project. The library compiles with no problems. I got the cyassl.lib file and placed it into my MASM project, referenced it with the includelib directive.

This bit of code prototypes the functions I need from the library

SSLv3_client_method PROTO
SSL_CTX_new PROTO method:DWORD
SSL_new PROTO ctx:DWORD
SSL_set_fd PROTO ssl:DWORD,sock:DWORD
SSL_connect PROTO ssl:DWORD
SSL_get_cipher PROTO ssl:DWORD
SSL_write PROTO ssl:DWORD,pReq:DWORD,sizeReq:DWORD
SSL_read PROTO ssl:DWORD,pBuf:DWORD,sizeBuf:DWORD
SSL_shutdown PROTO ssl:DWORD
SSL_free PROTO ssl:DWORD
SSL_CTX_free PROTO ctx:DWORD
SSL_load_error_strings PROTO
SSL_library_init PROTO


Once I build my MASM project I get these (I guess you can guess what follows :bg)

test.obj : error LNK2001: unresolved external symbol _SSLv3_client_method@0
test.obj : error LNK2001: unresolved external symbol _SSL_CTX_new@4
test.obj : error LNK2001: unresolved external symbol _SSL_new@4
test.obj : error LNK2001: unresolved external symbol _SSL_set_fd@8
test.obj : error LNK2001: unresolved external symbol _SSL_connect@4
test.obj : error LNK2001: unresolved external symbol _SSL_write@12
test.obj : error LNK2001: unresolved external symbol _SSL_read@12
test.obj : error LNK2001: unresolved external symbol _SSL_shutdown@4
test.obj : error LNK2001: unresolved external symbol _SSL_free@4
test.obj : error LNK2001: unresolved external symbol _SSL_CTX_free@4
test.obj : error LNK2001: unresolved external symbol _SSL_load_error_strings@0
test.obj : error LNK2001: unresolved external symbol _SSL_library_init@0


Lets take a moment to discuss the SSLv3_client_method function in a bit more detail. This is how the function is defined

CYASSL_METHOD* CyaSSLv3_client_method(void)
    {
        CYASSL_METHOD* method =
                              (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
                                                       DYNAMIC_TYPE_METHOD);
        CYASSL_ENTER("SSLv3_client_method");
        if (method)
            InitSSL_Method(method, MakeSSLv3());
        return method;
    }


I tried adding __stdcall in front of the function name and also the extern prefix (not sure if you would even need something like that in a library) but that doesn't change anything. That function is also referenced in the header file

CYASSL_API CYASSL_METHOD *CyaSSLv3_client_method(void);

tried doing the same as above and yet again the library compiles nicely but there is no change as far as MASM build goes.

The only moves in some other direction I managed to make were these:-

1) Change the proto to

SSLv3_client_method PROTO C

then the error thrown while building in MASM is

test.obj : error LNK2001: unresolved external symbol _SSLv3_client_method

2) When compiling the project as C code in VC++ 2008 Express by using __stdcall I managed only to get about 5 times larger library file (?) with the same source code, but nothing besides that changed, the build errors are exactly the same.

Note: as far as I can understand, for c++ code, if you want to keep the function names non mangled you're supposed to add extern "C" prefix to function definitions. But, as this is c code what would be the point of compiling it as c++?

If you wish to inspect any source files, just speak up. I don't think any of my assembly is really relevant here as it compiles nicely.

Again, thanks for your time.

jj2007

Here is a very simple example calling a C object file from Masm:
.686
.model flat, stdcall

asmprint proto

.code
start:
mov eax, 12345
call asmprint
ret
end start


#include <stdio.h>

void __stdcall asmprint();

void __stdcall asmprint(){
unsigned int veax;
__asm mov veax, eax
printf("The number is %u - cute, isn't it?", veax);
}


Commandline for the C program:
"%ProgramFiles%\Microsoft Visual Studio 9.0\VC\bin\cl.exe" /nologo /Os /c /Zl /Fa /Fp TestAsmC.c

The linker commandline is
/merge:.text=.data \masm32\lib\msvcrt.lib TestAsmC.obj tmp_file.obj

Count the number of understrokes ... :thumbu

mkey

Thanks for your reply.

Maybe I missed something, but is there anything I wrote which leads to the assumption that I'm not aware there are two (2) underscores prior to the stdcall? Because it isn't so.

What does the /Os switch do? My cl.exe version does not support that option.

Also, since I'm trying to build a library, am I supposed to use lib.exe instead of link.exe?

jj2007

My "count the underscores" was half joking. I have never understood why C is so fuzzy with underscores and the like...
In any case: my two snippets work fine together. Are you able to build them?

Link.exe can be used to build a library.

C:\Program Files\Microsoft Visual Studio 10.0\VC\bin>cl /?
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 for 80x86
/Os favor code space



mkey

I find it that they just keep adding more underscores to replace the old stuff.

I'm encountering more (of the same, I assume) damned problems. This is what I did.

CYASSL_API CYASSL_METHOD *CyaSSLv3_client_method(void);
CYASSL_METHOD* CyaSSLv3_client_method(void)
    {
        CYASSL_METHOD* method =
                              (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
                                                       DYNAMIC_TYPE_METHOD);
        CYASSL_ENTER("SSLv3_client_method");
        if (method)
            InitSSL_Method(method, MakeSSLv3());
        return method;
    }


changed a bit to

CYASSL_METHOD* __stdcall CyaSSLv3_client_method(void);
CYASSL_METHOD* __stdcall CyaSSLv3_client_method(void)
    {
        CYASSL_METHOD* method =
                              (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
                                                       DYNAMIC_TYPE_METHOD);
        CYASSL_ENTER("SSLv3_client_method");
        if (method)
            InitSSL_Method(method, MakeSSLv3());
        return method;
    }


CYASSL_API defines the scope of the function, depending on the build type. I think it's safe to just have it replace with what is needed here.
CYASSL_METHOD is the structure name, obviously.

Modified only one function, just to see if I can get it working. That /Os switch is definitively not present, there doesn't seem to be anything like that, either. Anyway, I used this shell script to compile 33 .c files

@echo off
del *.obj
del dir.lst
del cyassl.lib
for %%a in ("*.c") do cl /nologo /c /Zl /Fa /Fp %%a
dir *.obj /b>dir.lst
lib /verbose /subsystem:windows /out:cyassl.lib @dir.lst


the /Os being omitted. I added both paths to the path variable.

It builds the cyassl.lib library out of 33 .obj files, but still I get the same error in MASM.

Could the problem arise from the fact I'm invoking an SSLv3_client_method which is being defined as CyaSSLv3_client_method in the .h file? Apparently, if I invoke CyaSSLv3_client_method instead, I get a

LINK : fatal error LNK1104: cannot open file "uuid.lib"

So it is true, you cannot see past the choices you don't understand.

Yet another edit:

I tried compiling your example with this shell script

@echo off
del *.obj
del code.exe
cl /nologo /c /Zl /Fa /Fp code.c
ml /c /coff /Cp asm.asm
link /subsystem:windows /merge:.text=.data E:\masm32\lib\msvcrt.lib code.obj asm.obj
pause


No go, the app does not start. I'll start my VM XP and try to debug it. The program seems to be working normally, but it doesn't output anything.

Edit 67:

I modified your .c code above a bit, to reflect this

#include <windows.h>
#include <winuser.h>

void __stdcall asmprint();

void __stdcall asmprint(){
MessageBeep(-1);
}


and the compile script accordingly

@echo off
del *.obj
del code.exe
cl /nologo /c /Zl /Fa /Fp code.c
ml /c /coff /Cp asm.asm
link /subsystem:windows /merge:.text=.data E:\masm32\lib\user32.lib code.obj asm.obj
pause


This works normally, the app beeps and exits.

mkey

More "development". This also works

.686
.model flat, stdcall

asmprint proto c

.code

start:

mov eax, 12345
call asmprint
ret

end start


Note the proto c definition.

#include <windows.h>
#include <winuser.h>

void asmprint();

void asmprint(){
MessageBeep(-1);
}


No more __stdcall. Now onto the build scripts.

@echo off
cl /nologo /c /Zl /Fa /Fp code.c
ml /c /coff /Cp asm.asm
link /subsystem:windows E:\masm32\lib\user32.lib code.obj asm.obj
pause


"Exe version".

@echo off
cl /nologo /c /Zl /Fa /Fp code.c
lib /verbose /subsystem:windows /out:beep.lib code.obj
ml /c /coff /Cp asm.asm
link /subsystem:windows E:\masm32\lib\user32.lib beep.lib asm.obj
pause


"Lib version". From all of this I gather the blasted cyassl.lib only needs to be built and then finally use the proto c declarations to have the functions properly linked in MASM. But that still isn't happening, I must have done some extremely stupid error somewhere.

hutch--

two things, look up your compiler notation for its correct form of EXTERN C and make sure the prototyping matches in terms of calling convention (STDCALL or C). From memory you must use the EXERN C notation to avoid C++ name mangling as this will prevent successful cross module calling between MASM and CL.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

mkey

I don't think that's an issue as this is c code. If you put extern "c" you get a "string" error. I'm compiling this as c code, extern "c" is a c++ thing. Lost good 4-5 hours today while figuring that point out. Also, another fun fact, the VC IDE will compile source files depending on the file extension, disregarding the setting in the project properties. That one killed off a nice part of my sanity allotment for today.

Additionally, both of the above beep.lib examples work as intended, so I have to assume the "proto c" & "void function()" and "proto" & "void __stdcall function()" pairs work as intended in my environment.

Yet another (this time not a repeatable one) problem has surfaced. If I use any of the beep.lib libraries from above in my MASM project, the program refuses to build, it throws me a

LINK : fatal error LNK1104: cannot open file "uuid.lib"

I said OK, I must be losing my mind but OK, I'll just open up another RadASM project, an empty one and try to use this small lib there. Again, the same LNK1104 error. I close RadASM IDE, start it again and suddenly the damned beep.lib allows the project to build, as long as you pair the proto / function declaration in c properly. Probably there was something borked up in the IDE regarding the include libraries and whatnot.

Still no luck on the cyassl.lib front, though. I even tried redefining return function types, the library compiles nicely but the build in MASM still has unresolved external symbols. I know what can probably be done about this, just compile a cyassl.dll and then create a library to go with it, it will work nicely (probably), but that doesn't explain what's going on. After all this pain it would be nice to get a solution.

mkey

One more (last probably) update:

I redid the entire cyassl project, used the Pelles package to compile and build; set the __stdcall calling convention in project properties and checked the "Undecorate exported __stdcall functions" option. Still nothing :/

dedndave

that can probably be done, but not easily by someone new to assembly language
you would have to look at each module and deal with minor issues regarding stack frames, parms, etc

mkey

You misunderstood me. I'm not in any way new to assembly and when I say "redid" I mean "taken the source files from the cyassl package, created a new project in Pelles, changed the directory structure and handled some minor issues so that the library compiles normally". It was never my intention to recode the entire library in asm.

Anyway, the damned thing compiles now. What I thought may be the culprit, in fact was; sort of. Since this library is intended to supplement/surpass the OpenSSL library, it just redefines some of their own functions using OpenSSL function names. Example:

#define SSLv3_server_method CyaSSLv3_server_method

For some reason, Pelles IDE/compiler ignore these (there is no conditional defines around those defines, mind you) so I just used the original function names, prefixed with "Cya".

CyaSSLv3_client_method PROTO
CyaSSL_CTX_new PROTO method:DWORD
CyaSSL_new PROTO ctx:DWORD
CyaSSL_set_fd PROTO ssl:DWORD,sock:DWORD
CyaSSL_connect PROTO ssl:DWORD
CyaSSL_get_cipher PROTO ssl:DWORD
CyaSSL_write PROTO ssl:DWORD,pReq:DWORD,sizeReq:DWORD
CyaSSL_read PROTO ssl:DWORD,pBuf:DWORD,sizeBuf:DWORD
CyaSSL_shutdown PROTO ssl:DWORD
CyaSSL_free PROTO ssl:DWORD
CyaSSL_CTX_free PROTO ctx:DWORD
CyaSSL_load_error_strings PROTO
CyaSSL_library_init PROTO
SetErrorString PROTO :DWORD,:DWORD


I also had to add msvcrt.lib, but there are still some external functions the linker doesn't recognize.

cyassl.lib(internal.obj) : error LNK2001: unresolved external symbol ___ftoll
cyassl.lib(dh.obj) : error LNK2001: unresolved external symbol ___ftoll
cyassl.lib(dh.obj) : error LNK2001: unresolved external symbol ___log
cyassl.lib(integer.obj) : error LNK2001: unresolved external symbol ___chkstk
cyassl.lib(integer.obj) : error LNK2001: unresolved external symbol ___llmul


The __ftoll function I can't find anywhere on the web.
The __log is far too general name.
The __chkstk is declared in psxrtl.inc and the corresponding lib, but the inclusion of that library in my MASM project does not solve the problem.
The __llmul function I haven't found neither in the include files.

These functions aren't mentioned in the cyassl source files, neither.

Any light you may shed on these new issues would be greatly appreciated, even more so since it seems I'm rather close to compiling this blasted library.

dedndave

maybe these are part of the c-compiler initialization routines
with some luck, someone in here may be able to help
i think this is down Clive's ally   :P


mkey

Well, get that good man over here asap :D

Btw, I used dumpbin on the compiled library, /symbols switch.

009 00000000 UNDEF  notype       External     | ___log
014 00000000 UNDEF  notype       External     | ___ftoll
00B 00000000 UNDEF  notype       External     | ___chkstk
00D 00000000 UNDEF  notype       External     | ___llmul


Not sure what I hoped to find in there, but there it is nevertheless. The /disasm switch fails with a "LINK : warning LNK4195: unable to load MSDIS109.DLL" error even though the dll is present in the bin folder.

EDIT:

jj2007, there is no library in MASM that corresponds to that name. I'll look into creating one.

Maybe I wasn't clear on that point, but the errors above I get when building the MASM project, not while building the library.

EDIT2:

While doing some text searches (lol noobish but effective) I found a few libs that seem to be using/defining __ftoll function, namely

crt.lib
crtmt.lib
pocrt.lib
glaux.lib

I shall dig more.

dedndave

QuoteLNK4195: unable to load MSDIS109.DLL" error even though the dll is present in the bin folder.
the DLL may have to exist in the path environment variable, as well as in the same folder as LINK