News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

mangled names linking modules

Started by markallyn, September 12, 2017, 02:17:56 AM

Previous topic - Next topic

markallyn

Helllo everyone,

I've come back to masm after several years playing with linux.  I'm still on a Linux OS but running under Wine...which seems to work OK.  Because I've been away so long I've forgotten how to link modules, with the result that function names are being mangled and I can't figure out how to fix the problem.  Here's the calling program:\

Quoteinclude \masm32\include\masm32rt.inc

EXTERN _mult2int@0:PROC
.STACK   4096



.DATA   
   num1   DWORD   412
   num2   DWORD   36
   prtr   BYTE   "first dword is %d", 13, 10, 0
   result   BYTE   "The sum of the two DWORDS is %d", 13,10,0
   imulrlt   BYTE   "The product of the two DWORDS is %d", 13, 10, 0



.CODE

   main   PROC   near
   nop
   nop
   push   ebp
   mov   ebp, esp
   mov   eax, num1
   push   eax
   push   OFFSET prtr
   call   crt_printf
   add   esp, 8
   mov   eax, num1
   push   eax
   mov   eax, num2
   push   eax
   call   add2int
   add   esp, 8
   push   eax
   push   OFFSET result
   call   crt_printf
   add   esp, 8

   mov   eax, num1
   push   eax
   mov   eax, num2
   push   eax
   call   _mult2int@0
   push   eax
   push   OFFSET   imulrlt
   call   crt_printf
   add   esp, 8

   pop   ebp
   mov    esp, ebp
   mov   eax,   1
   mov   ebx,   0
   int   80h
   
   main   ENDP
;END main

   add2int   PROC   near
   push   ebp
   mov   ebp, esp
   mov   eax, [ebp+8]
   mov   edx, [ebp+12]
   add   eax, edx
   pop   ebp
   ret
   add2int   ENDP
END

And here is the little called program:

Quote;imul module
.486
.model flat, STDCALL
;include \masm32\include\masm32rt.inc
PUBLIC   mult2int
.STACK   4096

.CODE

mult2int PROC NEAR STDCALL PUBLIC
   push    ebp
   mov   ebp, esp

   mov   eax, [ebp+8]
   mov   edx, [ebp+12]
   imul   eax, edx
   pop   ebp
   ret
mult2int   ENDP
END

Plese note that I have commented out the include line.

I compile the calling program with ml.exe and link.exe.  In the link step I include the called program as imul.obj.  Both modules assemble without problems, but fail in the link step.  When I look at the function name in the imul.obj it is decorated as _mult2int@0.  But the linker refers to a even more highly decorated function name by adding an additional underscore and complaining about an unresolved symbol.

Any help would be appreciated.

Mark Allyn

Vortex

Hello markallyn,

Welcome to the forum.

You need to modify the two lines below as the STDCALL calling convention adds automatically a leading underscore the external symbols :

EXTERN _mult2int@0:PROC

Removing the underscore will do the job :

EXTERN mult2int@0:PROC

call   _mult2int@0

modified to

call   mult2int@0


Checking include \masm32\include\masm32rt.inc :

      .486                                      ; create 32 bit code
      .model flat, stdcall                      ; 32 bit memory model
      option casemap :none                      ; case sensitive

Vortex

Hi markallyn,

The 32-bit and 64-bit versions of Windows does not use interrupts. You use the Windows API functions to communicate with the operating system services. Here is a quick example :

include     \masm32\include\masm32rt.inc

add2int     PROTO :DWORD,:DWORD
mult2int    PROTO :DWORD,:DWORD

.data

x   dd  412
y   dd  36

msg1    db 'x + y = %d',13,10,0
msg2    db 'x * y = %d',13,10,0

.code

start:

    invoke  add2int,x,y
    invoke  crt_printf,ADDR msg1,eax

    invoke  mult2int,x,y
    invoke  crt_printf,ADDR msg2,eax   

    invoke  ExitProcess,0

END start

markallyn

Greetings, Vortex

Yes, that did the job!  I'm very grateful. But, I do remain confused on how the symbol resolution works.  Here's why.  Using dumpbin on the called function obj file shows that the symbol there is _mult2int@0, that is, with a prepended underscore.  The code is stdcall because of the included masm32rt.inc.   The caller is also stdcall because of the same include masm32rt.inc.  Naively (which I certainly am) I would have expected that the linker would attempt to match the two symbols and could because they have exactly identical names.  And not otherwise. I had expected that the stdcall in the caller code would produce exactly the same symbol as I found in the Dumpbin'd called obj file.  Perhaps you could elucidate?

BTW, I am not knew to the forum.  I stopped posting about 5 years ago when I went to Linux--not knowing about Wine and I reckoned that I would have to give up coding masm.  I felt bad about that because the contributors such as yourrself were so friendly and helpful.

Thanks again.  I will no doubt be back for more.

Regards,
Mark

markallyn

Greetings again, Vortex,

I looked at your second posting to me and tried the invoke Exit Process, 0.  The code ran thru mult2int without a problem, but then seg faulted.  (I had replaced the interrupt, as you suggested.  Any thoughts.

I also looked at your use of PROTO with regard to mult2ints and using invoke to call it.  I don't "get" how PROTO works with the linker.  Clearly, in some sense it is an alternative to the EXTERN keyword.  Can it be used as a substitute for linking an external function?

Thanks,
Mark

aw27

Hello markAllyn!

Quote
symbol there is _mult2int@0, that is, with a prepended underscore
Masm adds the underscore for you. :t

Here is a simple example, using both extern and proto.


; Caller function

.486

.model flat, stdcall
option casemap :None

EXTERN mult2int@8:PROC
mult2int equ <mult2int@8>

includelib \masm32\lib\msvcrt.lib
printf proto C :ptr, :vararg

.data
format1 db "%u",10,0 ; print unsigned

.code

main proc
push 012345678h
push 14
call mult2int

invoke printf,offset format1, eax, edx
ret
main endp

end main



; called function

.486

.model flat, stdcall
option casemap :None

.code

mult2int proc val1:dword, val2:dword
mov eax, val1
mul val2
ret
mult2int endp

end


You don't need to declare the called function as PUBLIC, procedures are PUBLIC by default.
And you don't need to use NEAR attributes in the procedure, you are working in a single code SEGMENT. There are also flaws... use a debugger to find them and fix the exception.





markallyn

Good morning, aw27,

I found the offending code causing the seg fault.  It was the line about four from the end in which I coded mov esp, ebp.  Removing that eliminated the seg fault problem.

I am still not entirely clear on the name resolution.  I understand that STDCALL adds the underscore.  But, why doesn't it also add an additional @0?  I take it that it only adds the pieces that are missing?

So, is it true that if I use PROTO I don't need EXTERN?  From the documentation (version 6.1) it seems I can use INVOKE with either PROTO or EXTERN which would seem to indicate that the latter are providing the same functionality as far as linking is concerned.

Thank you for taking an interest in this matter.  I appreciate your generosity.

Regards,
Mark

aw27

You need to practice a little and things will become clear for you.  :t

Note that you must not write EXTERN _mult2int@0:PROC but EXTERN _mult2int@8:PROC because you have 2 parameters each use 4 bytes in the stack.

Quote
So, is it true that if I use PROTO I don't need EXTERN
Yes. But for INVOKE you need PROTO. However, 64-bit MASM does not provide INVOKE. Still, there are equivalent macros and 3rd party assemblers from this site that do INVOKE in 64-bit.

markallyn

Hi aw27,

I'm still wrestling with this one, but your last post was very helpful.  Especially the bit about @8 rather @0.  I have been googling like crazy to find out the significance of the postpended stuff and without any luck.  I couldn't remember it from days long passed.

If you have the time to look at Vortex's second post to my initial inquiry you will see that he uses no decoration at all in his proto statement.  How does that work?

Thanks much,
Mark

aw27

Note that the way I declared the procedure in the callee, the assembler knows that there are 2 parameters to clear:
mult2int proc val1:dword, val2:dword
the way you did it:
mult2int PROC NEAR STDCALL PUBLIC
the assembler believes there are no parameters, so you needed to do it manually and you did not.
You noticed the exception. You removed the direct cause of the crash but did not prevent a memory leak.
BTW, protos have no decoration.



Vortex

Hi markallyn,

My apologies for the late reply. The PROTO statement does the decoration according to the STDCALL naming scheme.

For example, MessageBoxA takes four parameters.

int WINAPI MessageBoxA(
  _In_opt_ HWND    hWnd,
  _In_opt_ LPCTSTR lpText,
  _In_opt_ LPCTSTR lpCaption,
  _In_     UINT    uType
);


MessageBoxA PROTO :DWORD,:DWORD,:DWORD,:DWORD

A DWORD means four bytes. 4 parameters * 4 bytes = 16. The decoration will look like :

_MessageBoxA@16


Checking \masm32\include\user32.inc, you will see this line too :

MessageBox equ <MessageBoxA>

The leading underscore is added by the STDCALL calling convention.

Another example, the API function AllocConsole does not take any parameters. The result will be :

_AllocConsole@0

ExitProcess taking one parameter ( 1 parameter * 4 bytes = 4 )

_ExitProcess@4

For more information, you can check Agner Fog's excellent work :

Quote5. Calling conventions for different C++ compilers and operating systems
    This document contains details about data representation, function calling conventions, register usage conventions, name mangling schemes, etc. for many different C++ compilers and operating systems. Discusses compatibilities and incompatibilities between different C++ compilers. Includes information that is not covered by the official Application Binary Interface standards (ABI's). The information provided here is based on my own research and therefore descriptive rather than normative. Intended as a source of reference for programmers who want to make function libraries compatible with multiple compilers or operating systems and for makers of compilers and other development tools who want their tools to be compatible with existing tools.
     
    File name: calling_conventions.pdf

http://agner.org/optimize/

markallyn

Vortex, aw27,

Thanks much to both of you.  Yes, I did notice (via dumpbin /SYMBOLS imul.obj) that after I made the change to the PROC statement to recognize the two DWORDs the new name was _mult2int@8.  Made all the difference.  There is still a question remaining, but I've got to go install a new clothes washer....

Question for aw27.  Why is there a memory leak?  Where is it happening?

Regards to both of you.

Mark


aw27

Quote
Why is there a memory leak?  Where is it happening?

Mark,
If you disassemble mult2int proc val1:dword, val2:dword you will see "ret 8" in the end of the procedure. This does not happen with mult2int PROC NEAR STDCALL PUBLIC. In this last case if you exit the program with ret instead of ExitProcess it would crash.

markallyn

Good morning aw27.

Very interesting.  When you wrote about a leak I couldn't see where it could come from since I wasn't playing with the heap--at least as far as I knew.  While we're on the subject of leaks, do you happen to know any "canned" leak detector.  In the LInux world it's Valgrind.

Regards.
Mark

aw27

Quote from: markallyn on September 13, 2017, 10:22:35 PM
Very interesting.  When you wrote about a leak I couldn't see where it could come from since I wasn't playing with the heap--at least as far as I knew.  While we're on the subject of leaks, do you happen to know any "canned" leak detector.  In the LInux world it's Valgrind.
It depends on the programming language, I have used various.
For MASM probably you have to resort to WinDbg if necessary, but I really never used it for that.
For gross cases it is enough to look at  Taskmanager and watch the working set grow without explanation.  :biggrin:
These is more for heap leaks. Stack leaks usually end in a crash, but not always.
If you use exception handling and canaries stack leaks are easily detected. But in MASM most people does not, including me.