News:

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

How to import external function values?

Started by Alloy, December 06, 2007, 12:35:29 PM

Previous topic - Next topic

Alloy

I can code Extern Sleep but not others like Extern MessageBox.
We all used to be something else. Nature has always recycled.

evlncrn8

because MessageBox should be MessageboxA or MessageBoxW ?

Alloy

Thanks, that helped. But it's still crashing.

This is the code:

includelib kernel32.lib
includelib user32.lib
extern MessageBoxA: proc
extern ExitProcess: proc

.data
mytitle db '64 Bit Message Box', 0
mymsg db 'Hello World!', 0

.code
main proc
  mov r9d, 0       ; uType = MB_OK
  lea r8,  mytitle   ; LPCSTR lpCaption
  lea rdx, mymsg   ; LPCSTR lpText
  mov rcx, 0       ; hWnd = HWND_DESKTOP
  sub rsp,20h
  call MessageBoxA
  add rsp,20h
  mov ecx, eax     ; uExitCode = MessageBox(...)
  call ExitProcess
main endp
End


After ml64 /nologo /Zi /Zd /c code.asm then link /nologo /SUBSYSTEM:WINDOWS /DEBUG /DEBUGTYPE:cv code.obj /entry:main the executable produced crashes somewhere in the MessageBox function.

Thanks again.
We all used to be something else. Nature has always recycled.

feryno

Hi,
I don't know what does the macro
main proc
but MessageBoxA crashes on Vista when unaligned stack (rsp must be aligned at dqword = align 16)
this should work without macro:

main: sub rsp,8*(4+1) ; this alignes stack at 16
xor r9,r9 ; smaller opcode than mov r9d,0
lea r8,mytitle
lea rdx,mymsg
xor ecx,ecx ; smaller opcode than mov rcx,0
call MessageBoxA
; you needn't ExitProcess, you can exit using smaller code:
; eax=exit code
add rsp,8*(4+1) ; restore rsp
ret ; return to kernel32.dll and exit

Alloy

We all used to be something else. Nature has always recycled.

VonKyrin

I have to start out by saying that I'm an Assembly Language newbie. I've coded in assembler a few times over the years and took a C/Assembler class in college. But, I've recently read Kip Irvine's book and started coding Win32 in Assembler. So, I'm likely to have lots of questions for this forum.

One problem that I came across was: when I tried to recompile my x86 Assembly code (probably only about a page of code) into x64, I got it to compile but the MessageBox function call was basically ignored when it ran. I found this thread while searching for answers.

This thread actually got me started on the right track, but as I researched more, I found that there is a lot more to the issue than has been stated in the thread so far.

To just come straight out and say it: x64 is not only different because of the new registers. It is also different because 64 bit Windows is different. There are several issues involved between WOW64 (Windows 32 on Windows 64) and the new 64 bit kernel.

One of the differences that has been alluded to here is that the Win64 libraries such as kernel32.lib (has the 32 bit name but is actually 64 bit which is kinda confusing) have been recompiled with the new 64 bit compiler. (I don't want to get into explaining this too deeply but on a Vista 64 bit machine there are actually two totally different versions of kernel32 - a 32 bit version for WOW64 and the 64 bit version for the main OS which is still named kernel32 even though it's 64 bit). The Visual C++ 2008 compiler compiles things quite differently when you turn on the 64 bit compiling options. Now, don't get confused. You can continue to do things like they've been done since about the 386, by just setting the compiler options to compile 32 bit. But, with the 64 bit options on, it's a whole new "ball game".

The bottom line is that because the new Win32(Win64) has been compiled as x64 code (on the non-Itanium versions) there are completely new rules for calling Win32 API function in x64.

One of the big differences is how it expects parameters to be passed. This is what makes the older INVOKE function no longer functional in an x64 program. Parameters in x64 are COMPLETELY different than Win32 parameters in x86. Now, when you are writing your own functions you can pass parameters any way you like as long as it gets the job done, but in x64 Win32 you have to follow the same rules that Win32 follows (at least when you call Win32 functions).

The biggest difference with x64 Win32 is that it expects parameters to be passed by register NOT on the stack. It's actually more complicated than that, but that's kind of the core of why everything is so different in x64 (beyond the use of QWORD registers). An over simplification of the new parameter rule is: the first four parameters are passed by register in RCX, RDX, R8, and R9 and any additional parameters are passed on the stack. But the first "gotcha" is that even though the first four parameters are not passed on the stack, the rule is that you still have to allocate stack space for them by pushing the stack pointer up. AND, you have to allocate stack space for all four even if you only have one parameter. Also don't forget, in x64 it's a QWORD wide stack not a DWORD wide stack. If you disassemble some Visual C++ code, you should see that C++ allocates all the stack space it's going to need before it calls functions by moving the stack pointer. Then before the function ends it subtracts the stack pointer back to where it started.

The following hyper-links will give you most of the details:

http://msdn2.microsoft.com/en-us/magazine/cc300794.aspx
http://msdn2.microsoft.com/en-us/library/ew5tede7.aspx
http://www.uninformed.org/?v=4&a=1
http://msdn2.microsoft.com/en-us/library/zthk2dkh.aspx
http://msdn2.microsoft.com/en-us/library/9z1stfyw(VS.80).aspx
http://msdn2.microsoft.com/en-us/library/7kcdt6fy(VS.80).aspx
http://developer.apple.com/documentation/Darwin/Conceptual/64bitPorting/MakingCode64-BitClean/chapter_4_section_10.html
http://www.quequero.org/X64_Assembly

Good luck with your x64 Win32 programming! I'm sure I'll have some questions you can answer pretty soon.