Sign in to follow this  
Glak

help with nasm code

Recommended Posts

I'm trying to do some assembly programming so my first goal is to be able to call an assembly function from C++. Here is what I have so far: test.cpp
#include <iostream>
using namespace std;

extern "C" int TimesThree(int i);

int main()
{
	int x=5;
	x=TimesThree(x);
	cout<<x<<endl;

	return 0;
}

tt.asm:
global _TimesThree

_TimesThree:
	push	ebp
	mov	ebp, esp
	mov	eax, [ebp+8]
	imul	eax, [eax], 3
	leave
	ret

so what I do is: nasm -f obj tt.asm cl /EHsc test.cpp tt.obj it gives a warning about converting OMF to COFF but if I try to fix that by changing nasm's output format to coff it doesn't work. So anyway and exe is produced but it always crashes. I am assuming that it is in the assembly code but I think that I followed the description of how to do the C calling convention in the nasm docs pretty well Well if anyone knows how to fix this please help.

Share this post


Link to post
Share on other sites
According to this snippet from the NASM manual, Chapter 6: Output Formats

Quote:

Note that although Microsoft say that Win32 object files follow the COFF (Common Object File Format) standard, the object files produced by Microsoft Win32 compilers are not compatible with COFF linkers such as DJGPP's, and vice versa. This is due to a difference of opinion over the precise semantics of PC-relative relocations. To produce COFF files suitable for DJGPP, use NASM's coff output format; conversely, the coff format does not produce object files that Win32 linkers can generate correct output from.


Poking around these google results, the solution appears to be either switch to MASM or switch to GCC or some non-microsoft compiler/linker.

Share this post


Link to post
Share on other sites
I am not exactly sure what leave does behind the scenes... I think it fiddles with the stack pointer for use with local variables.

When I have written assembly functions that were called from C I have never used the leave instruction.

I have always used

pop EBP
ret


Try running the debugger and step through in disassembly mode and see where the crash is occuring.

Edit: The little assembler snippet relates to the __cdecl calling convention. The calling function is responsible for adjusting ESP.

(This is purely from memory so feel free to correct me if I am mistaken)

[Edited by - Adam Hamilton on March 19, 2007 5:00:48 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by Adam Hamilton
I am not exactly sure what leave does behind the scenes... I think it fiddles with the stack pointer for use with local variables.


Quoth the Intel manuals... "The LEAVE instruction copies the frame pointer (in the EBP register) into the stack pointer register (ESP), which releases the stack space allocated to the stack frame. The old frame pointer (the frame pointer for the calling procedure that was saved by the ENTER instruction) is then popped from the stack into the EBP register, restoring the calling procedure's stack frame"

It's perfectly valid to have both (NASM syntax)


foo:
PUSH EBP
MOV EBP, ESP
; Allocate local variable space on the stack (SUB, normally)
CALL bar
; Free local variable space on the stack (ADD, normally)
POP EBP
RET

bar:
ENTER 0, 0 ; 0 bytes of local variables, first nesting level
INC EAX
LEAVE ; Cleanup
RET




Or, indeed, some combination thereof - although I suspect you might want to be careful with using LEAVE without a matching ENTER (EDIT: Slightly more careful perusal of the manuals pseudocode statement of the operation suggests that this is actually okay, so long as you manually keep track of the nesting levels (if appropriate)).

I'm more used to hand writing the second, although if I'm mixing ASM with C code, I'm more used to my particular GCC cross compiler using the former so I stick with that.

Share this post


Link to post
Share on other sites
thanks everyone, still having problems though

So I triedI fooling around with trying to get OMT/obj to work by adding BITS 32 but it didn't work, so I tried MinGW (g++)

I went to the minGW page (worst website ever) and downloaded the stuff. I installed it and added it to my path, but it didn't want to work so I am calling it with the full name. So I tried to get a minimal C++ program running but it wanted a WinMain instead of a main so I ended up with the following:


#include <iostream>
using namespace std;
extern "C" int TimesThree(int i);
#include <windows.h>

int WINAPI WinMain (HINSTANCE hInstance,
HINSTANCE hPrevInstance,
PSTR szCmdLine,
int iCmdShow)
{
//MessageBox (NULL, "Hello", "Hello Demo", MB_OK);
int x=5;
cout<<TimesThree(x)<<endl;

return (0);
}



and my tt.asm as before, though I added the BITS 32

BITS 32
global _TimesThree

_TimesThree:
push ebp
mov ebp, esp
mov eax, [ebp+8]
imul eax, [eax], 3
leave
ret



then I used:

nasm -f coff tt.asm
\MinGW\bin\g++ -o test.exe test.cpp tt.o

for the error I get:

(.text+0x114): undefined reference to `TimesThree'

Share this post


Link to post
Share on other sites
Guest
This topic is now closed to further replies.
Sign in to follow this