News:

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

GoLink and VC object files

Started by Paul, January 09, 2009, 04:56:12 PM

Previous topic - Next topic

Paul

Hello All,

I am trying to GoLink my application with .obj files that began life as C source. GoLink fails, stating:

The following symbols were not defined in the object file or files:-
_free
_memset
_malloc
Output file not made

I identified (see http://msdn.microsoft.com/en-us/library/abx4dbyh.aspx) msvcr90.dll as the suitable DLL most likely to resolve these symbols. I changed my .asm source to include a #DYNAMICLINKFILE directive for this DLL; then re-assembled and re-linked. Same results.

So...I PEVIEWed the DLL and noticed that, among the DLLs EXPORT symbols, there was no '_free'. (There were symbols "_freea" and "_free_s"). But I also noticed that there was a mere 'free' (and 'malloc', 'memset', etc.). So, at Jeremy's suggestion I wrote wrapper functions in my .asm program providing function names "_free", "_malloc", etc., and within those functions INVOKEd functions "free" and "malloc."

Well, in conjunction with the #DYNAMICLINKFILE directive, this linked cleanly. However, when I run the .exe I get two Windows errors:

1. Runtime error R6034, followed by
2."The application failed to initialize properly (0xc0000142)" which means "{DLL Initialization Failed} Initialization of the dynamic link library %hs failed. The process is
    terminating abnormally."

From what little I understand of this, Windows is complaining that I tried to load a DLL without using a 'manifest.' I see no mention of manifests in the GoAsm and GoLink docs. I suspect they are created by the MS linker as part of Visual Studio building.

I sure would like to circumvent this problem and continue my happy use of the "Go" tools. Can anyone shed light on this problem?

Thank you.

-Paul



Vortex

#1
Hi Paul,

Welcome to the Masm forum.

Instead of msvcr90.dll, you can use msvcrt.dll shipped with Windows 98SE\2000\XP\Vista. Generally, I prefer to use a very small C run-time startup module to perform the initial jobs like parsing the command-line parameters. All C functions declared in C source codes are prefixed with an underscore in the object module files. I wrote a small tool named undecor.exe to undecorate \ remove those leading underscores in the object files.

A quick example :


#include <stdio.h>

int main(int argc,char *argv[])
{
char *p=(char *)malloc(128);
printf("Address of allocated memory = %X",p);
free(p);
return 0;
}


undecor.exe removes all the underscores and this is the disassembled module created with Agner Fog's tool objconv.exe :


_text   SEGMENT PARA PUBLIC 'CODE'                      ; section number 3
;  Communal section not supported by MASM

main    PROC NEAR
        push    esi                                     ; 0000 _ 56
        push    128                                     ; 0001 _ 68, 00000080
        call    malloc                                  ; 0006 _ E8, 00000000(rel)
        mov     esi, eax                                ; 000B _ 8B. F0
        push    esi                                     ; 000D _ 56
        push    offset ??_C@_0CB@NCLHPPMK@Address?5of?5allocated?5memory?5?$DN?5?$CFX@; 000E _ 68, 00000000(d)
        call    printf                                  ; 0013 _ E8, 00000000(rel)
        push    esi                                     ; 0018 _ 56
        call    free                                    ; 0019 _ E8, 00000000(rel)
        add     esp, 16                                 ; 001E _ 83. C4, 10
        xor     eax, eax                                ; 0021 _ 33. C0
        pop     esi                                     ; 0023 _ 5E
        ret                                             ; 0024 _ C3
main    ENDP

_text   ENDS


Here is how to build the project with MS Visual Studio Express 2005 C/C++ compiler and GoLink :


cl /c /Oty2 /Zl /Gs /GS- /Fomalloctest.OBJ malloctest.c
undecor malloctest.obj
\goasm\golink /console /entry mainCRTStartup malloctest.obj crt0\consCRT0.obj kernel32.dll msvcrt.dll


consCRT0.obj is the small C run-time startup module assembled with GoAsm.


[attachment deleted by admin]

Paul

Quote from: Vortex on January 09, 2009, 07:10:07 PM
Hi Paul,

Welcome to the Masm forum.

Instead of msvcr90.dll, you can use msvcrt.dll shipped with Windows 98SE\2000\XP\Vista. Generally, I prefer to use a very small C run-time startup module to perform the initial jobs like parsing the command-line parameters. All C functions declared in C source codes are prefixed with an underscore in the object module files. I wrote a small tool named undecor.exe to undecorate \ remove those leading underscores in the object files.

Thank you, Vortex, for your welcome and your reply.

Per your suggestion, I was able to GoLink successfully by using msvcrt.dll. I would again note that this DLL seems not to contain exports for, say, '_malloc.' But it does contain an export for 'malloc.' Thus I still needed my wrapper functions (passing the stack unchanged from '_malloc' to 'malloc', etc.). It works great.

I readily confess that I don't quite understand what you are doing with undecor.exe, but it sounds interesting. Can you explain in more detail how you use it?

A word about my background: I am (was) an expert mainframe assembly language programmer who works for a software company. My long history in such software has doubtless prejudiced me against nearly all high-level languages, especially "C" whose typed idiom frustrates me at every turn. Although I am relatively green in the x86 world, I am enjoying it immensely and look forward to learning from this board.

Thank you, again.

Paul

Vortex

Hi Paul,

Analyzing the functions exported by msvcrt90.dll with dumpbin :

\masm32\bin\dumpbin /EXPORTS  msvcr90.dll


.
.
.
1308  51B 000639DF malloc
.
.
.


The original function does not have a prepending underscore. The same applies also for msvcrt.dll It's the object module file where you can identify the functions prefixed with underscores. GoAsm does not add the underscores. In the case of ml.exe or cl.exe, the situation is more complicated. MessageBoxA, an API following the STDCALL convention and taking 4 parameters is "decorated" like the following :
_MessageBoxA@16 ; 4 parameter * 4 bytes per parameter = 16

Why MS or other vendors have to conform to some name decorating or mangling specifications?

From Agner Fog's calling conventions manual :

Quote8 Name mangling

Name mangling (also called name decoration) is a method used by C++ compilers to add
additional information to the names of functions and objects in object files. This information
is used by linkers when a function or object defined in one module is referenced from
another module. Name mangling serves the following purposes:

1. Make it possible for linkers to distinguish between different versions of overloaded
functions.
2. Make it possible for linkers to check that objects and functions are declared in
exactly the same way in all modules.
3. Make it possible for linkers to give complete information about the type of unresolved
references in error messages.
Name mangling was invented to fulfill purpose 1. The other purposes are secondary
benefits not fully supported by all compilers.

The minimum information that must be supplied for a function is the name of the function
and the types of all its parameters as well as any class or namespace qualifiers. Possible
additional information includes the return type, calling convention, etc. All this information is
coded into a single ASCII text string which looks cryptic to the human observer. The linker
does not have to know what this code means in order to fulfill purpose 1 and 2. It only needs
to check if strings are identical.

Each brand of C++ compiler uses its own name mangling scheme. Hitherto, there has been
no need to standardize name mangling because the object files produced by different
compilers were incompatible anyway for other reasons. However, since data representation,
calling conventions, and other details are now being standardized to an increasing degree in
the official ABI (Application Binary Interface) standards of new operating systems, there is
no reason not to standardize name mangling schemes as well.
Unfortunately, few compiler vendors have cared to publish their name mangling schemes.
This is the reason why I have studied the name mangling schemes of several different C++
compilers and published the detailed results here.

http://www.agner.org/optimize/calling_conventions.pdf

To summarize all :

a) Unless you don't specify the switch /ms=decorate for ms linker, GoAsm does not decorate functions.
b) Microsoft, Borland and other vendors have specific decoration shemes to create object files. The name mangling specifications are intended primarily to support the C++ language.
To maintain compatibility ml.exe and cl.exe are both using the same decoration scheme.

Reading Agner's manual, you will notice that C functions are prefixed with an underscore when they are passed to object files. This is why GoLink cannot resolve those functions. The linker assumes that the leading underscore is a part of the original function name. A function can be exported natively with the undescore so it's practically impossible for the linker to do the correct interpretation if it's the case of name decoration or not. There are two solutions : Writing wrapper functions or removing the underscore from object files. My choice was to create undecor.exe. The tool reads an object file and determines all the external functions. If it finds a function with a leading undercore, it removes the symbol _  so that GoLink can identify correctly all the external functions.

Vortex

#4
To explain better how undecor.exe works, this time I removed manually the leading underscores using a hex editor.

Here is how you see the external functions in the object module :



Now, copy the character strings to override the underscore and insert the NULL character to terminate the strings :



Notice that this manual editing is not the safest method and this is why it's preferable to use a tool like undecor.exe to automate the task.

To build the project :

a)Assemble the source code.
b)Edit the object file with a hex editor.
c)Link the modified object module.

[attachment deleted by admin]

donkey

Hi Paul,

Welcome to the forum.

For myself I try to avoid the vcrt but Vortex is right, the malloc function is there. You can also do it my way by using the malloc COM interface directly.

// This is from my header files, you can also use #dynamiclinkfile msvcrt.dll
#DEFINE LINKVCRT

invoke malloc,[nBytes]


#include "macros.a" // For the CoInvoke macro

CoMallocAlloc FRAME nBytes
uses ebx
LOCAL pIMalloc :D

invoke CoGetMalloc,1,offset pIMalloc
CoInvoke(pIMalloc,IMalloc.Alloc,[nBytes])
push eax
CoInvoke(pIMalloc,IMalloc.IUnknown.Release)
pop eax
RET
ENDF

CoMallocFree FRAME pMemory
uses ebx
LOCAL pIMalloc :D

invoke CoGetMalloc,1,offset pIMalloc
CoInvoke(pIMalloc,IMalloc.Free,[pMemory])
push eax
CoInvoke(pIMalloc,IMalloc.IUnknown.Release)
pop eax
RET
ENDF

CoMallocGetSize FRAME pMemory
uses ebx
LOCAL pIMalloc :D

invoke CoGetMalloc,1,offset pIMalloc
CoInvoke(pIMalloc,IMalloc.GetSize,[pMemory])
push eax
CoInvoke(pIMalloc,IMalloc.IUnknown.Release)
pop eax
RET
ENDF
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable