News:

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

Having a problem calling procedures.

Started by r_miele, January 06, 2005, 05:42:00 PM

Previous topic - Next topic

r_miele

I am trying to call a procedure I wrote in a seperate ASM file.  I have the prototype in an include file which is being included in the main calling program.  When I attemp to link the program it gives me this error message:


program.obj(program.asm) : error L2029: '_WriteString@6' : unresolved external


The name of the function I wrote is just WriteString but it looks like the linker is looking for _WriteString@6.

This reminds me of name decoration with C++ but I thought MASM didn't use that.

If I change the name of the function to _WriteString@6 it just appends another @6.  Any ideas, thanks.

BigDaddy

I have to prefix an underscore to externals for my linker to link.  As I recall, MASM works this way, too.

Vortex

Hi r_miele,

There is something strange with the name decoration : @6  The stack should be dword aligned, so the compiler / assembler expects number of bytes passed as multiples of 4  Example: myfunction@4 , thisfunction@8 Or simply are you using 16-bit development tools?

If you coding in C/C++, you should declare your functions like:

#ifdef __cplusplus
extern "C" {
#endif
extern int __stdcall funcname(char *,char *)  /* stdcall calling convention */
#ifdef __cplusplus
}
#endif



MichaelW

#3
r_miele,

I don't understand how you could be getting any decoration with a 16-bit program, but did you include the separate ASM file in the main calling program?  In addition to the prototype you must include the procedure definition. Or is the procedure you're trying to call in a library?
eschew obfuscation

Vortex

r_miele,

My apologies, I missed that you posted at the 16 bit DOS Programming forum, please ignore my statements about 32-bit coding.

MichaelW,

I remember that Turbo C++ V3.0 used the decorated naming convention,this might be valid also for the old versions of MS C compilers ( plus old versions of ml.exe ) targetting the 16-bit environment.

MichaelW

Quote from: Vortex on January 06, 2005, 07:54:31 PM
I remember that Turbo C++ V3.0 used the decorated naming convention,this might be valid also for the old versions of MS C compilers ( plus old versions of ml.exe ) targetting the 16-bit environment.

I think it probably is valid for the MS compilers, but I was assuming that the calling program and the called procedure were both coded in ASM.
eschew obfuscation

r_miele

This is an example of whats going on in the calling program:


INCLUDE pm_proc.inc

greeting1 BYTE "Hello World!", 0

INVOKE WriteString, OFFSET ES:greeting1, 2, 2


This is the include file:

.CODE
WriteString PROTO STDCALL,
ptrString:PTR BYTE, ;Points to starting address of string.
row:BYTE, ;Row
column:BYTE ;Column


And this is the procedure file:

INCLUDE pm_proc.inc

WriteString PROC USES EDI EAX EBX ECX
ptrString:PTR BYTE, ;Points to starting address of string.
row:BYTE, ;Row
column:BYTE ;Column

;Calculate starting point on screen of string.
MOV EDI, 0B8000h
MOV EAX, row
SUB EAX, 1
MOV EBX, 80
MUL EBX
ADD EAX, col
MOV EBX, 2
MUL EBX
ADD EDI, EAX

MOV EBX, ptrString
L1:
MOV CL, ES:[EBX]
CMP CL, 0
JZ L2
ADD CH, 0700h
MOV [EDI], CX
INC EDI
INC EDI
INC EBX
JMP L1

L2:
RET
WriteString ENDP


Thanks for the replies so far guys! :U

MichaelW

#7
r_miele,

Is this supposed to be 16-bit code or 32-bit code? Without seeing your .MODEL and processor directives, in the order in which they appear in the source file, we can only guess.

Your PROC and PROTO statements, in addition to specifying the same number of parameters and the same parameter types, must specify the same langtype attributes. So if one specifies STDCALL, so must the other.

You would normally pass word-size parameters for 16-bit code and dword-size parameters for 32-bit code.

You cannot MOV an 8-bit or 16-bit parameter or variable into a 32-bit register.

Your include file contains no executable code, so it has no need for a .CODE directive. If the directive is intended to open a code segment in the main or procedure files, it would be better to place it directly in the file that contains the code segment being opened (where it would be obvious).

What is the ES: in the invoke statement for? Do you actually intend to pass the offset address of greeting1, relative to the segment specified by ES? If greeting1 is defined in the data segment and ES == DS then the override is unnecessary. If greeting1 is defined in the data segment and ES != DS, then the procedure will be passed an invalid address.

With INVOKE you should normally use ADDR rather than OFFSET. OFFSET will work for addresses that are known at compile time, but not for addresses that are actually locations on the stack, as would be the case if you were trying to pass a parameter or local variable from within a procedure.

If WriteString is in a separate object module or library, you need to assemble the calling program and then link it with the WriteString module or library. If you are working directly with the ASM source, you need to either place the procedure in the source for the calling program, or include it with an INCLUDE statement.
eschew obfuscation