[Webinar] Streamline your web hosting managementRegister Today

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1031
  • Last Modified:

Linking Assembler code to a __fastcall C function

How do I call the C function
int __fastcall QuickAllocate (int size);
from my assembly code? This is not inline assembler, but a real assembly code file, I use ml.exe to assemble it. If I use the code
...
extern @QuickAllocate@4:near
...
call @QuickAllocate@4
...
I get the linker error
"error LNK2001: unresolved external symbol _@QuickAllocate@4"

The assembler seems desperate to add the _ name decoration to the C function name, but that is not correct in the case of __fastcall, so even though I specify the correct name decoration it won't leave it alone.

Using VC++ 6.0 and ml version 6.11

0
mgrinnell
Asked:
mgrinnell
  • 7
  • 2
  • 2
  • +4
1 Solution
 
tdubroffCommented:
Intead of using _fastcall, try extern "C".  This should prevent name-mangling from occuring at all.  Then in your assembly just use extern QuickAllocate : near.
0
 
mgrinnellAuthor Commented:
Yes, that would definitely work, that's what it was before!  What I'm trying to do here is change the calling convention for performance, though. __fastcall is what I want, so I need to find out how to make the assembler let me do it.
0
 
tdubroffCommented:
Hmm, what performance gain are you supposed to get using __fastcall?
0
Live webcast with Pinal Dave

Pinal Dave will teach you tricks to help identify the real root cause of database problems rather than red herrings. Attendees will learn scripts that they can use in their environment to immediately figure out their performance Blame Shifters and fix them quickly.

 
sumant032199Commented:
I am not good in Assembly but what I think is you can get address of your C function very easily and using pointer to the function and then instructing assembler to start execution from that vector.
0
 
mgrinnellAuthor Commented:
I tried that too -- treating the function pointer as just an address and jumping to it. I had the same name decoration problem with that, i.e. even pretending QuickAllocate was just a data pointer it wouldn't let me use it without predefining it, and if I predefine it, the assembler insists on prepending an _ character when it tells the linker what to look for.
0
 
mgrinnellAuthor Commented:
tdubroff, when you use __fastcall, you can pass arguments in registers instead of pushing them on the stack and then popping them off.
0
 
alexoCommented:
[ VC++ 4.2 ]

The __fastcall calling convention passes the first two arguments of size doubleword (DWORD) or smaller in the ECX and EDX registers; the remaining arguments are pushed on the stack right to left.  The called function adjusts the stack, and no case translation takes place.

Name-decoration convention - At sign (@) is prefixed to names; an at sign @ followed by the number of bytes (in decimal) in the parameter list is suffixed to names.

----------

You can use a .DEF file to set an alias to the mangled ("decorated") name.
0
 
alexoCommented:
Some more:

The current 32-bit module-definition (.DEF) file syntax requires that __cdecl, __stdcall, and __fastcall functions be listed in the EXPORTS section without underscores (undecorated).
0
 
nils pipenbrinckCommented:
Hm...

I've done a lot asm programming under win32.. but I always used nasm or tasm... never masm.

Maybe I don't understood your problem: it's just, that your assembler puts a underscore before your symbol, right?

0
 
mgrinnellAuthor Commented:
That's right, the problem is just that I need to name the C function I want to call to masm. The plain name of the function is QuickAllocate; the decorated name is @QuickAllocate@4. No matter what I do, the assembler puts an underscore in front of any symbol I name.
0
 
nils pipenbrinckCommented:
Hm.. I have no idea execept switching to tasm or nasm.


nasm does no name decoration at all..

with tasm you can control the name decoration.. (using a .model switch)

Nils
0
 
Tommy HuiEngineerCommented:
The easiest way to get this to work is to use the compiler to help.

First create your calling program (which I call test.cpp)

#include <stdio.h>

extern "C"
{
      int __fastcall Foo();
}

int main(int argc, char* argv[])
{
      int a = Foo();
      printf("a = %d\n", a);
      return 0;
}

Note the declaration for Foo (which has __fastcall).

Next, create a dummy C++ file. We will use this dummy C++ to create the dummy stub for the assembly file. I call this file Foo.cpp

extern "C"
{
int __fastcall Foo()
{
      return 0;
}
}

Next on the command line, use

  cl /c /FA foo.cpp

to generate the foo.asm file:

      TITLE      foo.cpp
      .386P
include listing.inc
if @Version gt 510
..model FLAT
else
_TEXT      SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT      ENDS
_DATA      SEGMENT DWORD USE32 PUBLIC 'DATA'
_DATA      ENDS
CONST      SEGMENT DWORD USE32 PUBLIC 'CONST'
CONST      ENDS
_BSS      SEGMENT DWORD USE32 PUBLIC 'BSS'
_BSS      ENDS
_TLS      SEGMENT DWORD USE32 PUBLIC 'TLS'
_TLS      ENDS
FLAT      GROUP _DATA, CONST, _BSS
      ASSUME      CS: FLAT, DS: FLAT, SS: FLAT
endif
PUBLIC      @Foo@0
_TEXT      SEGMENT
@Foo@0      PROC NEAR
      push      ebp
      mov      ebp, esp
      xor      eax, eax
      pop      ebp
      ret      0
@Foo@0      ENDP
_TEXT      ENDS
END


You can then compare your assembly file to this one to find out what is different. Another possible method is to put your code in here. Either way, you should have no problems continuing.


0
 
mgrinnellAuthor Commented:
Thanks thui, but this is not exactly the problem I'm trying to solve. I have an existing fastcall function written in C, whose prototype looks like
  int __fastcall QuickAllocate (int size);
I want to call that function from an assembler module.  

What's interesting in your example, though, is the beginning of the assembler file. If version is > 510 (which I presume it is) the file starts with a .model statement instead of the old _TEXT SEGMENT DWORD USE32 etc.., which is what my assembler file starts with. Maybe there's a clue here, I don't know yet...
0
 
Tommy HuiEngineerCommented:
You would use the same technique, create a dummy .cpp file

extern "C"
{
extern int __fastcall QuickAllocate(int size);
}

void DummyCaller()
{
  QuickAllocate(3);
}

And generate the assembly file for it and compare with your program.
0
 
mgrinnellAuthor Commented:
This generated the same code that I already tried, e.g.

EXTRN      @QuickAllocate@4:NEAR

When I try to use this from my assembly code, the assembler generates instructions to the linker to try to link to _@QuickAllocate@4 instead of @QuickAllocate@4.
0
 
mgrinnellAuthor Commented:
A friend discovered the answer. fastcall is the Microsoft C compiler's replacement for syscall, but you actually have to still use syscall with masm. If I declare QuickAllocate as

extrn syscall @QuickAllocate@4:near

then the linker knows not to modify the function name by prepending an _ character.

I'm going to try to figure out how to post this solution to the Community Support topic area, too. Thanks to all for your help.

0
 
darinwCommented:
Hello everyone,

I am moving this question to the PAQ.

-- I am accepting one of mgrinnell's comments as an answer --

darinw
Customer Service
0

Featured Post

The Lifecycle Approach to Managing Security Policy

Managing application connectivity and security policies can be achieved more effectively when following a framework that automates repeatable processes and ensures that the right activities are performed in the right order.

  • 7
  • 2
  • 2
  • +4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now