G-Spider
发表于 2011-4-21 10:32:37
对于ml64.exe 均使用_fastcall方式,用masm64写独立汇编时还有其他很多不便之处,相比masm32。
Win64汇编语言与C语言混合编程
如果习惯了masm语法,个人推荐用JWasm。
1. JWasm is written in C ,开源。
2. C header files can be converted to include files ,所用头文件由sdk之类的c头文件所转,继承了c头文件多选择式定义的优点,比如32位64位头文件均可在一个文件中定义。
3. SSE4.2 are supported
4.precompiled JWasm binaries are available for DOS, Windows and Linux. For OS/2 and FreeBSD, makefiles are supplied.多平台。
5.JWasm is faster than Masm.
6.JWasm is free, no artificial license restrictions, can be used to create binaries for any OS.
7.JWasm is a free MASM-compatible assembler . masm32编写的源文件可以不加修改的用JWasm编译。
汇编器JWASM.EXE 集成了16,32,64位的编译模式,masm高级语法被一致支持,比如.if .endif ,ml64.exe则不包含;调用规则也具多样性,不再是ml64.exe单纯的fastcall。
如果头文件定义的很好,写一个程序,加上不同的编译选择,就有可能生成32位,64位的可执行文件。
形如编译命令:
;--- Win32/64 console application, uses WinInc v2+.
;--- It can be used to generate both Win32 and Win64 binaries:
;--- 32bit:
;---jwasm -coff -I\WinInc\Include WinXX_1.asm
;---link /subsystem:console /Libpath:\WinInc\Lib WinXX_1.obj
;--- 64bit:
;---jwasm -win64 -Zp8 -I\WinInc\Include WinXX_1.asm
;---link /subsystem:console /Libpath:\WinInc\Lib64 WinXX_1.obj
liangbch
发表于 2011-4-21 21:12:15
我一直在思考一个问题,是否能在32位模式下使用64位寄存器和一些64位指令。比如,在32位模式下,计算2个__int64的整数的和很费时,不得不使用adc指令,而使用64为寄存器和64位算术指令可以很快算出结果。
我尝试使用JWasm编译一个汇编文件,不使用win64参数,但是Jwasm总报错。
liangbch
发表于 2011-4-21 21:14:54
不是能否使用emit 绕开汇编器的限制。
gxqcn
发表于 2011-4-21 21:39:11
我一直在思考一个问题,是否能在32位模式下使用64位寄存器和一些64位指令。比如,在32位模式下,计算2个__int64的整数的和很费时,不得不使用adc指令,而使用64为寄存器和64位算术指令可以很快算出结果。
我尝试使 ...
liangbch 发表于 2011-4-21 21:12 http://bbs.emath.ac.cn/images/common/back.gif
也许可以尝试用 MMX 寄存器?(用 SSE2 指令 PADDQ)
liangbch
发表于 2011-4-21 22:33:41
尝试使用 emit 绕开编译器限制,在32位模式下使用64bit 指令。
编译成功。运行也不出现异常,但是结果不对。不知是我的指令写的有问题,还是确实在32位模式下不能运行64位指令。#include <stdlib.h>
#include <stdio.h>
void arrayAdd_c(__int64 *p1, __int64 *p2)
{
*p1 += *p2;
}
_declspec(naked)
void arrayAdd_asm( __int64 *p1, __int64 *p2)
{
__asm
{
push esi
push edi
movedi,
movesi,
moveax,
movedx,
addeax,
adcedx,
mov,eax
mov,edx
popedi
popesi
ret
}
}
_declspec(naked)
void arrayAdd_asm64( __int64 *p1, __int64 *p2)
{
__asm
{
push esi
push edi
movedi,
movesi,
//movrax,qword ptr
__asm _emit 0x67
__asm _emit 0x48
__asm _emit 0x8B
__asm _emit 0x07
//movrdx,qword ptr
__asm _emit 0x67
__asm _emit 0x48
__asm _emit 0x8B
__asm _emit 0x16
//addrax, rdx
__asm _emit 0x48
__asm _emit 0x03
__asm _emit 0xC2
//movqword ptr , rax
__asm _emit 0x67
__asm _emit 0x48
__asm _emit 0x89
__asm _emit 0x07
/*
movqmm0,qword ptr
movqmm1,qword ptr
paddq mm0, mm1
movqqword ptr , mm0
*/
popedi
popesi
ret
}
}
int main()
{
__int64 a1,a2,a3;
__int64 b1,b2,b3;
a1=a2=a3=12345678987654321I64;
b1=b2=b3=5000000000I64;
printf("a1=%I64d,a2=%I64d,a3=%I64d\n",a1,a2,a3);
arrayAdd_c(&a1,&b1);
arrayAdd_asm(&a2,&b2);
arrayAdd_asm64(&a3,&b3);
printf("a1=%I64d,a2=%I64d,a3=%I64d\n",a1,a2,a3);
}
liangbch
发表于 2011-4-21 22:35:10
贴出运行结果,可以看到a3的值不对,说明arrayAdd_asm64工作不正常。a1=12345678987654321,a2=12345678987654321,a3=12345678987654321
a1=12345683987654321,a2=12345683987654321,a3=12345679692687022
请按任意键继续. . .
liangbch
发表于 2011-4-21 22:36:07
在 函数 arrayAdd_asm64中,注释掉64位指令,改用MMX指令,发现结果是正确的。
G-Spider
发表于 2011-4-22 00:31:41
15# liangbch
呵呵,想法很大胆,我想也有很多人想过。生成32可执行文件,至少PE格式已指明了32位,rax高位就对你透明了。如果32位中用部分64寄存器和指令,我猜要切换模式,可能会有一些特权指令,ring3下也用不了,可什么时候切换呢?暂时没找到这样的例子,只好想象一下32位与64位的程序在时间片轮转中的情形。
以上都是个人猜测。
G-Spider
发表于 2011-4-27 15:12:11
JWasm的16/32/64是集成的,考虑到MS 的ml.exe 和ml64.exe 仍然可统一win32/win64编程.
调用规则上,win32多样,而win64只有fastcall (JWasm也如此)。所以为了调用的外观上一致,写了一个调用宏_invoke ,解决了这个问题。在编译和链接的时候,它们各自调用自己的include 和lib文件,源代码是共用的,干净凝练。
相关说明在代码中。
;---------------------------------------------------------------
;---------------------------------------------------------------
;--- Win32/Win64 simple GUI application. By G-Spider 2011
;--- Note: requires ml.exe \ml64.exe ,link.exe
;---------------------------------------------------------------
;--- X86
;--- ml /c /cofffile.ASM
;--- link/out:win32.exe /subsystem:windows /entry:main file.obj
;---------------------------------------------------------------
;--- X64
;--- ml64 /c/Zp8 /D _WIN64=1 file.ASM
;--- link /out:win64.exe /subsystem:windows /entry:main file.obj
;---------------------------------------------------------------
;---------------------------------------------------------------
;说明:ml.exe 和ml64.exe中有个命令选项:
;/D sysmbol=value 定义给定名字的文本宏。
;所以可以通过这个命令来自动选择源代码中的x86或x64部分.
;在x86中,默认不用设置/D sysmbol=value或设置/D _WIN64=0
;若选择ml64.exe编译,可以加上/D _WIN64=1即可
;/Zp 对结构指定的字节边界对齐
;---------------------------------------------------------------
ifndef _WIN64
_WIN64 equ <0>
endif
if _WIN64 eq 0 ;no -_WIN64 switch?
.386
.model flat, stdcall
rax equ <eax>
rbx equ <ebx>
rcx equ <ecx>
rdx equ <edx>
rsp equ <esp>
rbp equ <ebp>
rsi equ <esi>
rdi equ <edi>
;//如果x64的inc文件也合法的话,可以通用include ,只是路径不一样
;//一个是masm32\include 一个是masm64\include
includeuser32.inc
includekernel32.inc
else ;_WIN64不为0 开启64位
;//X64的inc文件可以写成如下形式
;//用晓风残月的生成def/inc64工具即可
extrn wsprintfA : proc
extrn MessageBoxA : proc
extrn ExitProcess : proc
;//
endif
option casemap:none
includelib kernel32.lib
includelib user32.lib
;================================================
;以下为通用调用宏
;================================================
;------------------------------------------------
; 参数翻转
;------------------------------------------------
reverseArgs macro arglist:VARARG
local txt,count
txt TEXTEQU <>
count = 0
for i, <arglist>
count=count+1
txt TEXTEQU @CatStr(i, <,> , <%txt> )
endm
if count GT 0
txt SUBSTR txt,1,@SizeStr(%txt)-1
endif
exitm txt
endm
;------------------------------------------------
; 一个x86\x64 invoke Macro
;------------------------------------------------
_invoke macro _Proc,args:VARARG
local count
local stack
local rspL
count= 0
if_WIN64 NE 0;//不等于0时,选择X64,fastcall
rspL = 20h
% for i,<args>
count=count+1
if count GT 4
rspL= rspL + 8h
endif
endm
count=rspL/16
count=count*16
if rspL EQ count
rspL=rspL+8
endif
sub rsp,rspL
count = 0
stack = 0
% for i,<args>
count= count + 1
if count EQ 1
mov rcx,i
elseif count EQ 2
mov rdx,i
elseif count EQ 3
mov r8,i
elseif count EQ 4
mov r9,i
elseif count GE 5
mov rax,i
mov qword ptr ,rax
endif
stack = stack + 8
endm
call
add rsp,rspL
else
% for i,< reverseArgs( args ) >
count = count + 1
push i
endm
call
endif
endm
;================================================
;以上为通用调用宏
;================================================
.data
imsg byte 'this invoke feels like 32bit',0
szFmt1 byte '%d',0
szFmt2 byte '%d %d',0
szFmt3 byte '%d %d %d',0
szFmt4 byte '%d %d %d %d ',0
.data?
Buffer dword 8 dup(?)
.code
main proc
;========================
_invoke wsprintfA,offset Buffer,offset szFmt1,10h
_invoke wsprintfA,offset Buffer,offset szFmt2,10h,16h
_invoke wsprintfA,offset Buffer,offset szFmt3,10h,16h,17h
_invoke wsprintfA,offset Buffer,offset szFmt4,10h,16h,17h,18h
;========================
_invoke MessageBoxA,0,offset imsg,offset Buffer,0
_invoke ExitProcess,0
main endp
end
gxqcn
发表于 2011-4-27 19:45:25
我只进行过嵌入式汇编,对楼上的独立的asm文件操作不熟悉。
据说64位下VC不支持内嵌汇编(消息可靠否),不知Intel的编译器是否还支持?