Using MinGW-w64 for 64bit applications on 64bit Windows.
1. 前言
使用 MinGW-w64 的工具與程式庫來編寫 64 位元程式,只要透過 Cygwin 其實非常簡單。
但如前文所述,Cygwin 目前只能編譯 32 位元的程式,使用的是 GCC 3.4.4 的版本,編譯的概念是 MinGW 與 Cygwin 程式庫二選一。
這裡要做的,則是將 Cygwin ,MinGW,MinGW-w64 視為不同的平台,以 cross compiler 的概念來進行編譯,分為三個步驟。
第一,重新安裝 Cygwin 的GCC為 4.3.4版本,可以呼叫 POSIX API 與 Windows API,但是執行時需要 cygwin1.dll。
第二,安裝 MinGW 來編譯 32 位元程式,編譯出來的是一般 Windows 32位元執行檔。
第三,安裝 MinGW-w64 來編譯 64 位元程式,編譯出來的是一般 Windows 64位元執行檔。
2. 重新安裝 Cygwin
要更新 Cygwin 的 GCC 為 4.3.4 版本,直接移除 c:\cygwin 這個目錄比較快,但是記得備份 c:\cygwin\home\Administrator 目錄下的檔案。
安裝的過程,請參考前文,到了套件選擇的步驟時,選擇 file, gcc4-core, gcc4-g++, make, vim 。
安裝完成後,進入 bash 輸入:
$ cc -v
Using built-in specs.
Target: i686-pc-cygwin
Configured with: /gnu/gcc/releases/packaging/4.3.4-3/gcc4-4.3.4-3/src/gcc-4.3.4/
configure --srcdir=/gnu/gcc/releases/packaging/4.3.4-3/gcc4-4.3.4-3/src/gcc-4.3.
4 --prefix=/usr --exec-prefix=/usr --bindir=/usr/bin --sbindir=/usr/sbin
(略)
Thread model: posix
gcc version 4.3.4 20090804 (release) 1 (GCC)
可知這次 GCC 版本為 4.3.4, 編譯目標為 i686-pc-cygwin。
以 a.c 為例,編譯出來的檔案,可以使用 file 來測試, 輸入:
$ file a.exe
a.exe: PE32 executable for MS Windows (console) Intel 80386 32-bit
可知為 PE 格式執行檔,但在檔案管理員中點選執行時,會產生找不到 cygwin1.dll 的錯誤,原因如前文所述。
另外,可以使用 objdump 反組譯來查看, 輸入:
$ objdump -d a.exe | grep '%esp,%ebp'
401001: 89 e5 mov %esp,%ebp
(略)
可知使用的是 32 位元暫存器。
這時候,如果要使用 -mno-cygwin 是不行的, 以 b.c 為例:
$ cc -o b b.c -mno-cygwin -mwindows
cc: The -mno-cygwin flag has been removed; use a mingw-targeted cross-compiler.
3. 安裝 MinGW
接下來到 http://mingw-w64.sourceforge.net/ 下載 mingw-w64-bin_i686-mingw_20100123_sezero.zip ,將壓縮檔內的 mingw32 目錄解壓縮到 c:\目錄內, 然後在 bash 內 輸入:
$ ln -s /cygdrive/c/mingw32 /mingw32
這個步驟讓我們能夠使用 /mingw32/bin/gcc 來進行編譯,輸入:
$ /mingw32/bin/gcc -v
Using built-in specs.
Target: i686-w64-mingw32
Configured with: ../gcc44-svn/configure --target=i686-w64-mingw32 --host=i686-w6
4-mingw32 --disable-multilib --disable-nls --disable-win32-registry --prefix=/mi
ngw32 --with-sysroot=/mingw32 --with-gmp=/mingw32 --with-mpfr=/mingw32 --enable-
languages=c,c++
Thread model: win32
gcc version 4.4.3 (GCC)
可知編譯目標為 i686-w64-mingw32。
以檔案 b.c 為例,輸入:
$ /mingw32/bin/gcc -o b b.c -mwindows
完成編譯後,以使用 file 來測試, 輸入:
$ file b.exe
b.exe: PE32 executable for MS Windows (GUI) Intel 80386 32-bit
可知為 32 位元 PE 執行檔。
使用 objdump 反組譯來查看, 輸入:
$ /mingw32/bin/objdump -d b.exe | grep '%esp,%ebp'
401001: 89 e5 mov %esp,%ebp
(略)
可知使用的是 32 位元暫存器。
4. 安裝 MinGW-w64
接下來到 http://mingw-w64.sourceforge.net/ 下載 mingw-w64-bin_x86_64-mingw_20100123_sezero.zip ,將壓縮檔內的 mingw64目錄解壓縮到 c:\目錄內。
製作 /mingw64 連結, 在 bash 內 輸入:
$ ln -s /cygdrive/c/mingw64 /mingw64
這個步驟讓我們能夠使用 /mingw/mingw64/bin/gcc 來進行編譯,輸入:
$ /mingw64/bin/gcc -v
Using built-in specs.
Target: x86_64-w64-mingw32
Configured with: ../gcc44-svn/configure --target=x86_64-w64-mingw32 --host=x86_6
4-w64-mingw32 --disable-multilib --disable-nls --disable-win32-registry --prefix
=/mingw64 --with-sysroot=/mingw64 --with-gmp=/mingw64 --with-mpfr=/mingw64 --ena
ble-languages=c,c++
Thread model: win32
gcc version 4.4.3 (GCC)
可知編譯目標為 x86_64-w64-mingw32。
以檔案 b.c 為例,輸入:
$ /mingw64/bin/gcc -o b b.c -mwindows
完成編譯後,以使用 file 來測試, 輸入:
$ file b.exe
b.exe: PE32+ executable for MS Windows (GUI)
可知為 64 位元 PE 執行檔。
使用 objdump 反組譯來查看, 輸入:
$ /mingw64/bin/objdump -d b.exe|grep '%rsp,%rbp'
401731: 48 89 e5 mov %rsp,%rbp
(略)
可知使用的是 64 位元暫存器。
5. 使用 GNU as 編寫 64 位元組合語言
安裝完 MinGW-w64 後,可以直接使用 /mingw64/bin/gcc 來組譯 GNU as 語法的 64位元組合語言。
舉例來說, 將下面的文字複製為 d.s 檔案:
.globl _main
.data
str: .string "hello"
.text
_main:
lea str, %rcx
call _printf
ret
之後輸入:
$ /mingw64/bin/gcc -o d d.s
即可組譯 d.s 為執行檔 d.exe, 輸入以下指令可執行
$ ./d
hello
6. 使用 ML64 編寫 64 位元組合語言
目前(2010) 並沒有 Masm615 這類隨書附贈的 64 位元 MASM 語法組譯器,不嫌麻煩的話,可以使用 Visual Studio 提供的 ML64 來進行組譯:
a) 安裝 Microsoft Visual Studio 2008, 完成加入這個連結:
$ ln -s '/cygdrive/c/Program Files (x86)/Microsoft Visual Studio 9.0/VC/bin/amd64' /vc
並且複製 libcmt.lib 這個檔案到工作目錄。
$ cp '/cygdrive/c/Program Files (x86)/Microsoft Visual Studio 9.0/VC/lib/amd64/libcmt.lib' .
b) 安裝 Microsoft SDK, 完成後複製 Kernel32.lib 到工作目錄。
$ cp '/cygdrive/c/Program Files/Microsoft SDKs/Windows/v6.0A/Lib/x64/Kernel32.lib' .
之後編寫以下程式為 e.asm 來進行測試:
printf PROTO
.data
s BYTE "hello",0
.code
main proc
lea rcx, s
call printf
ret
main endp
end
輸入以下指令來組譯:
$ /vc/ml64 -c e.asm
$ /vc/link e.obj libcmt.lib Kernel32.lib
即可組譯 e.asm 為執行檔 e.exe, 輸入以下指令可執行
$ ./e
hello
7. 總結
以 MinGW-w64,GNU as,或是 ML64 來編寫 64位元 C 語言或是組合語言非常方便, 提供給修習計算機組織的同學參考。
另外,64 位元與32位元呼叫 API 時的 ABI(Application Binary Interface) 差異很大, 要稍微留意。
Eih-Zhe Liang
ezliang@mail.dwu.edu.tw
cygwin下dll和lib的生成方法
luckythc | 03 四月, 2008 16:44
cygwin可以编译生成windows下供调用的dll,包括vc可识别的lib。
Cygwin-GCC : Cygwin自带了一个GCC, 用于把C/C++-Source编译成Cygwin平台下的EXE/DLL (使用Cygwin必须用其自带的GCC, 因为内部会生成一些针对于平台的特定的初始化代码, 如果用其余版本的GCC则很有可能导致程序不能正常运行.)
Cygwin-GCC : Cygwin自带了一个GCC, 用于把C/C++-Source编译成Cygwin平台下的EXE/DLL (使用Cygwin必须用其自带的GCC, 因为内部会生成一些针对于平台的特定的初始化代码, 如果用其余版本的GCC则很有可能导致程序不能正常运行.)
说明 - Cygwin-GCC :
在Cygwin-Shell中可直接使用gcc . 如下 :
gcc -shared xxx.c -o xxx.dll //编译成DLL, 注意, Cygwin-GCC默认导出所有的Function.
gcc -c xxx.c -o xxx.o //编译成OBJ
gcc xxx.c -o xxx.exe //编译成EXE
ar r xxx.lib xxx1.o xxx2.o //打包多个obj成一个Lib (非连接)
gcc xxx.c ./L aaa.dll -o xxx.exe //引用外部DLL生成EXE
gcc xxx.c yyy.c -o zzz.exe //连接多个C文件, 生成EXE.
gcc -I"/bin/include" -c xxx.c -o xxx.o //引用/bin/include目录下头文件,生成OBJ
gcc -L"dll.a" xxx.c -o xxx.exe //连接dll.a, 生成EXE
如果想知道编译时具体的信息, 可以使用--verbose这个编译选项, 对于了解GCC的工作是很有帮助的.
额外的,也可以写自己的导出Lib文件, 以方便其余程序引用DLL (如Cobol2002编译器就不支持直接引用DLL, 这个时候可以写一个Def, 并导出Lib文件, 便于Cobol2002使用)
具体方法如下:
1. 编译生成DLL :
如: gcc -shared MyTest.c -o MyTest.dll, 生成MyTest.dll.
2. 写一个DEF文件 (这里是MyTest.def), 简单的格式大致如下:
LIBRARY MyTest //这里的MyTest对应于MyTest.dll
EXPORTS
AllocMemory @1 //导出的第一个function : 对应于MyTest.dll里面的AllocMemory(...), 注意, 参数可不用写
ReadMemory @2 //导出的第二个function : 对应于MyTest.dll里面的ReadMemory-Function.
//注意: function可以不用全部导出, 可以只选择你需要的Function.
3. 用LIB工具(VC6有提供)生成LIB文件 (这里是MyTest.lib) :
lib /def:MyTest.def //默认生成的名称为MyTest.lib.
4. 到此生成完毕, 连接的时候只需要引用MyTest.lib即可, 但要注意XXX.exe 和MyTest.dll要放在同一目录下.
可以用 gcc --help 查看具体的命令 etc..
没有评论:
发表评论