2010年4月3日星期六

Cygwin 使用

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..

没有评论: