找回密码
 欢迎注册
楼主: gxqcn

[讨论] 用vc2008开发64位程序,懂的请进

[复制链接]
发表于 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位的可执行文件。
形如编译命令:

  1. ;--- Win32/64 console application, uses WinInc v2+.
  2. ;--- It can be used to generate both Win32 and Win64 binaries:
  3. ;--- 32bit:
  4. ;---  jwasm -coff -I\WinInc\Include WinXX_1.asm
  5. ;---  link /subsystem:console /Libpath:\WinInc\Lib WinXX_1.obj
  6. ;--- 64bit:
  7. ;---  jwasm -win64 -Zp8 -I\WinInc\Include WinXX_1.asm
  8. ;---  link /subsystem:console /Libpath:\WinInc\Lib64 WinXX_1.obj
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2011-4-21 21:12:15 | 显示全部楼层
我一直在思考一个问题,是否能在32位模式下使用64位寄存器和一些64位指令。比如,在32位模式下,计算2个__int64的整数的和很费时,不得不使用adc指令,而使用64为寄存器和64位算术指令可以很快算出结果。
  我尝试使用JWasm编译一个汇编文件,不使用win64参数,但是Jwasm总报错。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2011-4-21 21:14:54 | 显示全部楼层
不是能否使用emit 绕开汇编器的限制。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2011-4-21 21:39:11 | 显示全部楼层
我一直在思考一个问题,是否能在32位模式下使用64位寄存器和一些64位指令。比如,在32位模式下,计算2个__int64的整数的和很费时,不得不使用adc指令,而使用64为寄存器和64位算术指令可以很快算出结果。
  我尝试使 ...
liangbch 发表于 2011-4-21 21:12


也许可以尝试用 MMX 寄存器?(用 SSE2 指令 PADDQ)
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2011-4-21 22:33:41 | 显示全部楼层
尝试使用 emit 绕开编译器限制,在32位模式下使用64bit 指令。
编译成功。运行也不出现异常,但是结果不对。不知是我的指令写的有问题,还是确实在32位模式下不能运行64位指令。
  1. #include <stdlib.h>
  2. #include <stdio.h>

  3. void arrayAdd_c(__int64 *p1, __int64 *p2)
  4. {
  5.         *p1 += *p2;
  6. }

  7. _declspec(naked)
  8. void arrayAdd_asm( __int64 *p1, __int64 *p2)
  9. {
  10.         __asm
  11.         {
  12.                 push esi
  13.                 push edi
  14.                
  15.                 mov  edi, [esp+8+4]
  16.                 mov  esi, [esp+8+8]

  17.                 mov  eax,[edi]
  18.                 mov  edx,[edi+4]
  19.                 add  eax,[esi]
  20.                 adc  edx,[esi+4]
  21.                 mov  [edi],eax
  22.                 mov  [edi+4],edx

  23.        
  24.                 pop  edi
  25.                 pop  esi

  26.                 ret
  27.         }
  28. }

  29. _declspec(naked)
  30. void arrayAdd_asm64( __int64 *p1, __int64 *p2)
  31. {
  32.         __asm
  33.         {
  34.                 push esi
  35.                 push edi
  36.                
  37.                 mov  edi, [esp+8+4]
  38.                 mov  esi, [esp+8+8]

  39.                
  40.                 //mov  rax,qword ptr [edi]
  41.                 __asm _emit 0x67
  42.                 __asm _emit 0x48
  43.                 __asm _emit 0x8B
  44.                 __asm _emit 0x07

  45.                 //mov  rdx,qword ptr [esi]
  46.                 __asm _emit 0x67
  47.                 __asm _emit 0x48
  48.                 __asm _emit 0x8B
  49.                 __asm _emit 0x16

  50.                 //add  rax, rdx
  51.                 __asm _emit 0x48
  52.                 __asm _emit 0x03
  53.                 __asm _emit 0xC2

  54.                 //mov  qword ptr [edi], rax
  55.                 __asm _emit 0x67
  56.                 __asm _emit 0x48
  57.                 __asm _emit 0x89
  58.                 __asm _emit 0x07
  59.                
  60.                 /*
  61.                 movq  mm0,qword ptr [edi]
  62.                 movq  mm1,qword ptr [esi]
  63.                 paddq mm0, mm1
  64.                 movq  qword ptr [edi], mm0
  65.                 */
  66.                
  67.                 pop  edi
  68.                 pop  esi

  69.                 ret
  70.         }
  71. }


  72. int main()
  73. {
  74.         __int64 a1,a2,a3;
  75.         __int64 b1,b2,b3;

  76.         a1=a2=a3=12345678987654321I64;
  77.         b1=b2=b3=5000000000I64;
  78.        
  79.         printf("a1=%I64d,a2=%I64d,a3=%I64d\n",a1,a2,a3);

  80.         arrayAdd_c(&a1,&b1);
  81.         arrayAdd_asm(&a2,&b2);
  82.         arrayAdd_asm64(&a3,&b3);

  83.         printf("a1=%I64d,a2=%I64d,a3=%I64d\n",a1,a2,a3);

  84. }

复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2011-4-21 22:35:10 | 显示全部楼层
贴出运行结果,可以看到a3的值不对,说明arrayAdd_asm64工作不正常。
  1. a1=12345678987654321,a2=12345678987654321,a3=12345678987654321
  2. a1=12345683987654321,a2=12345683987654321,a3=12345679692687022
  3. 请按任意键继续. . .
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2011-4-21 22:36:07 | 显示全部楼层
在 函数 arrayAdd_asm64中,注释掉64位指令,改用MMX指令,发现结果是正确的。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2011-4-22 00:31:41 | 显示全部楼层
15# liangbch
呵呵,想法很大胆,我想也有很多人想过。生成32可执行文件,至少PE格式已指明了32位,rax高位就对你透明了。如果32位中用部分64寄存器和指令,我猜要切换模式,可能会有一些特权指令,ring3下也用不了,可什么时候切换呢?暂时没找到这样的例子,只好想象一下32位与64位的程序在时间片轮转中的情形。
以上都是个人猜测。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2011-4-27 15:12:11 | 显示全部楼层
JWasm的16/32/64是集成的,考虑到MS 的ml.exe 和ml64.exe 仍然可统一win32/win64编程.
调用规则上,win32多样,而win64只有fastcall (JWasm也如此)。所以为了调用的外观上一致,写了一个调用宏_invoke ,解决了这个问题。在编译和链接的时候,它们各自调用自己的include 和lib文件,源代码是共用的,干净凝练。
相关说明在代码中。
src.rar (3.27 KB, 下载次数: 1)
  1. ;---------------------------------------------------------------
  2. ;---------------------------------------------------------------
  3. ;--- Win32/Win64 simple GUI application. By G-Spider 2011
  4. ;--- Note: requires ml.exe \ml64.exe ,link.exe
  5. ;---------------------------------------------------------------
  6. ;--- X86
  7. ;--- ml /c /coff  file.ASM
  8. ;--- link  /out:win32.exe /subsystem:windows /entry:main file.obj
  9. ;---------------------------------------------------------------
  10. ;--- X64
  11. ;--- ml64 /c  /Zp8 /D _WIN64=1 file.ASM
  12. ;--- link /out:win64.exe /subsystem:windows /entry:main file.obj
  13. ;---------------------------------------------------------------
  14. ;---------------------------------------------------------------
  15. ;说明:ml.exe 和ml64.exe中有个命令选项:
  16. ;/D sysmbol=value 定义给定名字的文本宏。
  17. ;所以可以通过这个命令来自动选择源代码中的x86或x64部分.
  18. ;在x86中,默认不用设置/D sysmbol=value或设置/D _WIN64=0
  19. ;若选择ml64.exe编译,可以加上/D _WIN64=1即可
  20. ;/Zp[n] 对结构指定的字节边界对齐
  21. ;---------------------------------------------------------------

  22. ifndef _WIN64
  23.   _WIN64 equ <0>
  24. endif


  25. if _WIN64 eq 0        ;no -_WIN64 switch?
  26.   .386
  27.         .model flat, stdcall
  28.   rax   equ <eax>
  29.   rbx   equ <ebx>
  30.   rcx   equ <ecx>
  31.   rdx   equ <edx>
  32.   rsp   equ <esp>
  33.   rbp   equ <ebp>
  34.   rsi   equ <esi>
  35.   rdi   equ <edi>
  36.   ;//如果x64的inc文件也合法的话,可以通用include ,只是路径不一样
  37.   ;//一个是masm32\include 一个是masm64\include
  38.         include  user32.inc
  39.         include  kernel32.inc

  40. else    ;_WIN64不为0 开启64位
  41. ;//X64的inc文件可以写成如下形式
  42. ;//用晓风残月的生成def/inc64工具即可
  43.   extrn        wsprintfA   : proc
  44.   extrn        MessageBoxA : proc
  45.   extrn        ExitProcess : proc
  46. ;//
  47. endif
  48.   
  49.         option casemap:none
  50.   
  51.         includelib kernel32.lib
  52.         includelib user32.lib
  53. ;================================================
  54. ;以下为通用调用宏
  55. ;================================================
  56. ;------------------------------------------------
  57. ; 参数翻转
  58. ;------------------------------------------------
  59. reverseArgs macro arglist:VARARG
  60.   local txt,count
  61.          
  62.   txt TEXTEQU <>
  63.   count = 0
  64.   for i, <arglist>
  65.       count=count+1
  66.       txt TEXTEQU   @CatStr(i, <,> , <%txt> )
  67.   endm
  68.   if count   GT   0
  69.      txt SUBSTR     txt,1,@SizeStr(%txt)-1
  70.   endif
  71.   exitm txt
  72. endm

  73. ;------------------------------------------------
  74. ; 一个x86\x64 invoke Macro
  75. ;------------------------------------------------
  76. _invoke        macro   _Proc,args:VARARG
  77.                 local   count
  78.                 local   stack
  79.                 local   rspL

  80.   count= 0  
  81.   if  _WIN64    NE 0  ;//不等于0时,选择X64,fastcall
  82.       rspL = 20h           
  83.       %   for    i,<args>
  84.                  count=count+1
  85.                  if count GT 4
  86.                      rspL= rspL + 8h
  87.                  endif
  88.           endm
  89.           count=rspL/16
  90.           count=count*16
  91.           if rspL EQ count
  92.               rspL=rspL+8
  93.           endif
  94.       
  95.           sub rsp,rspL
  96.       
  97.           count   = 0
  98.           stack   = 0
  99.       %   for     i,<args>                        
  100.                   count  = count + 1
  101.                   if count EQ 1
  102.                          mov rcx,i
  103.                   elseif count EQ 2
  104.                          mov rdx,i
  105.                   elseif count EQ 3
  106.                          mov r8,i
  107.                   elseif count EQ 4
  108.                          mov r9,i
  109.                   elseif count GE 5
  110.                          mov rax,i
  111.                          mov qword ptr [rsp+stack],rax
  112.                   endif
  113.                   stack = stack + 8
  114.           endm
  115.           call    [_Proc]
  116.           add rsp,rspL
  117.   else
  118.       %   for i,< reverseArgs( args ) >
  119.           count = count + 1
  120.           push i
  121.       endm
  122.       call    [_Proc]   
  123.   endif

  124. endm
  125. ;================================================
  126. ;以上为通用调用宏
  127. ;================================================

  128. .data
  129. imsg   byte 'this invoke feels like 32bit',0
  130. szFmt1 byte '%d',0
  131. szFmt2 byte '%d %d',0
  132. szFmt3 byte '%d %d %d',0
  133. szFmt4 byte '%d %d %d %d ',0
  134. .data?
  135. Buffer dword 8 dup(?)

  136. .code
  137. main proc
  138. ;========================
  139.   _invoke wsprintfA,offset Buffer,offset szFmt1,10h
  140.   _invoke wsprintfA,offset Buffer,offset szFmt2,10h,16h
  141.   _invoke wsprintfA,offset Buffer,offset szFmt3,10h,16h,17h
  142.   _invoke wsprintfA,offset Buffer,offset szFmt4,10h,16h,17h,18h
  143.   
  144. ;========================
  145.   _invoke MessageBoxA,0,offset imsg,offset Buffer,0
  146.   _invoke ExitProcess,0

  147. main endp
  148.         end
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2011-4-27 19:45:25 | 显示全部楼层
我只进行过嵌入式汇编,对楼上的独立的asm文件操作不熟悉。
据说64位下VC不支持内嵌汇编(消息可靠否),不知Intel的编译器是否还支持?
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

小黑屋|手机版|数学研发网 ( 苏ICP备07505100号 )

GMT+8, 2024-5-2 11:32 , Processed in 0.047129 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表