機電之家資源網
單片機首頁|單片機基礎|單片機應用|單片機開發(fā)|單片機文案|軟件資料下載|音響制作|電路圖下載 |嵌入式開發(fā)
培訓信息
贊助商
32/64位SPARC上的Solaris遷移到x86上Linux的指南
32/64位SPARC上的Solaris遷移到x86上Linux的指南
 更新時間:2009-8-12 16:52:50  點擊數(shù):0
【字體: 字體顏色

表 2 解釋了不同風格的 Linux 上的不同級別的 C 編譯器之間的區(qū)別。

表 2. 不同級別的 C 編譯器之間的區(qū)別

注意: * 在 64 位的 IBM JDK 1.4.2 for Linux on x86 中并不支持 LinuxThreads。Java 支持 NPTL 64 位線程庫。

還有,如果您要在 SLES9 上編譯 C++ 程序,并將其部署到 RHEL4 上,那么就需要使用 compat 庫,它在包 compat-libstdc++-33-3.2.3-47.3.i386.rpm 中。之所以需要這個 compat 庫,是因為在 SLES9 和 RHEL4 之間需要不同級別的 ABI 兼容性。SLES9 遵循 LSB 1.3 標準,而 RHEL4 遵循 LSB 2.0 標準。

32 位到 64 位移植的考慮
要將應用程序從 32 位環(huán)境移植到 64 位環(huán)境中,您有兩種選擇:

  • 讓應用程序可以容許 64 位操作
  • 開拓目標平臺上的 64 位操作能力

首先,將應用程序在一個 64 位的環(huán)境中使用,然后試圖開拓目標平臺的 64 位能力。

盡管 32 位的應用程序通常都可以在 64 位的目標平臺上很好地運行,但是在 64 位環(huán)境中啟用應用程序也是非常重要的,因為有些第三方的產品會以 64 位模式啟動,而不提供 32 位版本的庫對象。

在遷移到 64 位的環(huán)境中時,您需要決定是否繼續(xù)支持該產品的 32 位版本。如果需要支持這兩個版本,那么就需要適當?shù)臅r間進行打包和測試。

開拓 64 位的能力應該是在實現(xiàn)容許 64 位操作之后的下一個步驟。在開始這種嘗試之前,應該仔細衡量一下開拓 64 位能力的優(yōu)點。

應用程序從 32 位到 64 位的遷移這個主題在很多出版物中已經進行了介紹(例如 參考資料 中列出的 AIX 5L Porting Guide 的第 3 章)。

體系架構和系統(tǒng)特有的區(qū)別
現(xiàn)在,讓我們來看一下 Solaris 和 x86 上的 Linux 之間一些特定于體系架構和系統(tǒng)的區(qū)別,包括:基本的數(shù)據類型,內核參數(shù)的設置,體系架構特有的區(qū)別,endianness,系統(tǒng)調用,信號,數(shù)據類型,以及線程庫。

參考資料 提供了在進行大型的移植嘗試時,需要考慮的一個可行的檢查清單。

基本的數(shù)據類型和對齊方式
在一個系統(tǒng)中有兩種不同類型的數(shù)據類型:基本數(shù)據類型(basic data type)和派生數(shù)據類型(derived data types)。

基本數(shù)據類型 是由 C 和 C++ 語言規(guī)范所定義的所有數(shù)據類型。表 3 對 x86 上的 Linux 和 SPARC 上的 Solaris 這兩者的基本數(shù)據類型進行了比較。

表 3. 比較 Linux 和 Solaris 的基本數(shù)據類型

在兩個平臺之間或 32 位與 64 位模式之間移植應用程序時,您需要考慮不同環(huán)境中對齊設置之間的區(qū)別,從而避免出現(xiàn)性能降低和數(shù)據崩潰的危險。

表 4 介紹了 x86 上的 Linux 中以字節(jié)為單位的對齊值。

表 4. x86 上的 Linux 中的對齊值(以字節(jié)為單位)

注意: 對齊取決于所使用的編譯器開關。這些開關控制著“l(fā)ong double”類型的大小。i386 應用程序的二進制接口規(guī)定這個大小是 96 位,因此 -m96bit-long-double 在 32 位模式中是默認值,F(xiàn)代的體系架構(Pentium 及更新的體系架構)更喜歡將“l(fā)ong double”按照 8 字節(jié)或 16 字節(jié)進行對齊。在符合 ABI 規(guī)范的數(shù)組或結果中,這是不可能的。因此指定一個 -m128bit-long-double 會將“l(fā)ong double” 按照 16 字節(jié)邊界進行對齊,它會為“l(fā)ong double”填充 32 位的 0。

系統(tǒng)派生的數(shù)據類型
派生數(shù)據類型是已有的基本類型或其他派生類型的一個派生物或結構。系統(tǒng)派生數(shù)據類型 可以根據所采用的數(shù)據模型(32 位或 64 位)和硬件平臺而具有不同的字節(jié)大小。

表 5 給出了 Linux 上與 Solaris 上不同的一些派生數(shù)據類型。

表 5. Solaris 和 Linux 中的派生數(shù)據類型

機器特有的代碼的例子
在下面這些情況中需要機器特有的代碼:

  • 獲得堆棧指針
  • 原子鎖

在 Linux-x86 平臺上的堆棧指針可以實現(xiàn)為:

清單 1. 在 Linux-x86 上獲取堆棧指針

在 Solaris,下面這段示例代碼讓您可以獲取堆棧指針:

清單 2. 在 Solaris 上獲取堆棧指針

在 Linux x86 上,您可以使用一個 compare 和 swap 操作來實現(xiàn)原子鎖。例如,下面是 Linux x86 上使用 compare 和 swap 操作的一個簡單實現(xiàn):

清單 3. Linux x86 上的 Compare 和 swap 操作

在 Solaris SPARC 上,加鎖的原子操作可以如下實現(xiàn):

清單 4. Solaris 上的原子鎖

字節(jié)順序(endianness)
由于 SPARC 采用的是 big-endian,而 x86 采用的是 little-endian,因此您需要考慮 endianness 的問題。

Endianness 的問題在以下這些情況中都變得非常重要:移植客戶機要在異構網絡環(huán)境中進行通信的應用程序,將數(shù)據永久地保存到磁盤上,產品跟蹤(在 SPARC 平臺上所生成的跟蹤信息必須能夠在 x86 平臺上正確地格式化),以及其他相關領域。IA-64 Linux 內核默認使用 little-endian,但是也可以使用 big-endian 的字節(jié)順序。

系統(tǒng)調用
Solaris 系統(tǒng)調用使用了一種在 Linux 上是不可用的不同的命名和簽名機制,這在“從 Solaris 向 Linux on POWER 遷移指南” 中已經介紹過了。以下這些系統(tǒng)調用現(xiàn)在在 RHEL4 中可以使用:

  • Waitid
  • Putmsg
  • putpmsg
  • Getmsg
  • getpmsg

Curses 庫
Linux 用于 xurses 庫的那些庫函數(shù)比 Solaris 更加類似于 AIX。例如,諸如 addwch 之類的函數(shù)在 Linux 中不受支持。有些函數(shù),例如 mvchgat,在 Solaris 中不可用。當您將與 curses 有關的代碼從 Solaris 移植到 Linux 上時,很多代碼都需要重寫。

Terminal IO
Solaris 中的 termio 結構與 Linux 中的這個結構是不同的。Linux 中的 termio 結構多了幾個域,您可以使用它們來設置輸入和輸出速度。

Linux 中 termio 結構的定義位于 /usr/include/bits/termios.h 文件中,而 Solaris 中 termio 的定義則位于 /usr/include/sys/termios.h 文件中。

IOCTL
執(zhí)行 ioctl 可以使用的選項在 Solaris 和 Linux 中是不同的。例如,要獲得資源的利用情況,您可以向 ioctl 系統(tǒng)調用傳遞 PIOCUSAGE:

Return_code = ioctl("/proc/<pid>", PIOCUSAGE, &buff) ;

在 Linux 中,您必須直接從 /proc/<pid> 目錄中讀取相關的文件來獲得相關信息,在 Linux 上不能使用 PIOCUSAGE 選項。在這兩種情況中,pid 是正在執(zhí)行命令的當前進程的進程 id。

另外一個例子是當您希望獲取該進程的堆信息時。在 Solaris 中,要獲取堆信息,您可以使用下面的方法:

Return_code = Ioctl("/proc/<pid>",PIOCPSINFO,&psinfo)

在這段代碼中,psinfo 是一個 struct prpsinfo 結構;Prpsinfo.pr_size 就給出了該進程的堆大小。

在 Linux 中,正在使用的頁數(shù)可以從 /proc/<pid>/mem 和 /proc/<pid>/stat 中獲得。頁面大小可以使用系統(tǒng)調用 getpagesize 獲得。這兩個值(頁數(shù)和頁面大。┑某朔e就是堆的當前大小。

Getopt
在 Linux 中,只有在設置了 POSIXLY_CORRECT 環(huán)境變量之后,getopt 調用才遵循 POSIX 標準。

如果設置了環(huán)境變量 POSIXLY_CORRECT,那么對參數(shù)的分析一碰到非選項參數(shù)(以“-”開始的參數(shù))就立即停止。 其余的參數(shù)全部被解釋為非選項參數(shù)。

調用 shell 腳本之間的區(qū)別
如果 shell 腳本使用了 su 命令,就會派生一個子 shell。這種行為與 Solaris 不同,在 Solaris 中, su 命令不會派生一個新 shell。

如果您在 Linux 上執(zhí)行命令 su - root,那么 ps 命令的輸出就會如下所示:

在這段代碼中,30931 是進程 31004 的祖先進程。您可能要修改一些受到這種關系影響的腳本。

重啟動時的設備處理
從 RHEL4 開始,Linux 就采用了熱插拔子系統(tǒng) udev 的概念。它提供了可配置的動態(tài)設備命名的支持。設備配置是在每次重新啟動時動態(tài)構建的。

例如,如果您有一個新目錄 /dev/dsk,那么系統(tǒng)可能并不知道它的存在,這個目錄在重啟之后可能就會丟失。為了避免 /dev/dsk 目錄丟失的問題,可以建立一個 /etc/udev/devices/dsk 目錄,這樣系統(tǒng)在重新啟動時就可以維護這種信息,因此即使系統(tǒng)重新啟動之后,/dev/dsk 也依然會存在。

內核參數(shù)
在 Solaris 中,內核參數(shù)可以在 /etc/system 文件中進行設置。在 Linux 中,內核參數(shù)可以使用 sysctl 系統(tǒng)調用進行修改。可以修改的參數(shù)在 /proc/sys/kernel 中都可以看到,procfs 的支持對于 sysctl 正常工作來說是必需的。

信號
信號之間的區(qū)別在“Technical guide for porting applications from Solaris to Linux”中已經詳細介紹過了。其他值得注意的一些區(qū)別是 Solaris 有 38 個信號,而 Linux 使用了 31 個信號,而且 sigaction 結構也不相同。例如,在 Linux 中,sigaction 接口如下所示:

清單 5. Linux 中的 sigaction 結構

在 Solaris 中,sigaction 結構如下所示:

清單 6. Solaris 中的 sigaction 結構

由于所支持的信號個數(shù)不同,siginfo_t 結構也不相同。對于 Linux,這可以在 /usr/include/bits/signal.h 文件中找到;對于 Solaris,這可以在 /usr/include/sys/siginfo.h 文件中找到。

線程支持和 IPC
有關 Linux on POWER 與 Solaris 之間進行移植的出版物已經介紹了 Solaris 線程與 Linux 的 POSIX 線程(由 NPTL 庫提供)之間的區(qū)別。

我的經驗是,如果應用程序早已在 Solaris 上就使用了 POSIX 線程,那么它們移植到使用基于 NPTL 線程的 Linux 上就非常簡單。在 Linux 上還可以利用一些新特性,例如進程共享互斥鎖,因此 Solaris 中使用 pthread 互斥鎖和條件變量的那些有關 IPC 機制的代碼在 Linux 中都可以使用。

自然語言的支持
在 Solaris 中對于自然語言的支持的代碼也與 Linux 中可能會有所不同,或者它們只是名字有所不同而已。在 Solaris 中大部分的 locales 和代碼頁在 Linux 中都有對應的內容。

結束語
從 Solaris 到 x86 上的 Linux 的移植工作在大部分情況中只是一個重新編譯的過程,或者對編譯器/鏈接器開關稍微進行一些修改。有時可能需要對某些平臺特有的內容進行一些修改,例如加鎖、內存映射、線程,等等。您應該了解一下這些差異,并對移植好好進行一下規(guī)劃,從而減少移植所需要的時間。

 
Solaris 被認為是風格與 Linux™ 最為接近的一種 UNIX®,但是對于程序的遷移來說,它們在諸如內存映射、線程以及對自然語言的支持等領域還是有很大區(qū)別的。這個移植指南可以為您在計劃將程序移植到 Linux/x86 上時提供一些建議,并且?guī)椭斫忾_發(fā)環(huán)境和體系架構之間的區(qū)別。

在各種風格的 UNIX 中,Solaris 被認為與 Linux 的風格最為接近。因此在開始將大型的基于 Unix 的應用程序移植到 Linux 上之前,首先要從 Solaris 中挑選出那些依賴于操作系統(tǒng)的代碼。即便如此,在那些依賴于體系架構的領域、內存映射、線程或一些特殊的領域(例如系統(tǒng)管理和自然語言的支持),它們之間還是有差異的。

本文對這些差異進行了討論,并加以對比,從而能夠對您從運行在 32/64 位 SPARC 體系架構上的 Solaris 遷移到運行在 x86 體系架構上的 Linux 提供一些幫助。對于 Solaris 來說,這種討論是基于版本 8 及更新的版本的。對于 Linux 來說,這種討論著重于那些在基于 x86 處理器的服務器上可用的發(fā)行版本:SUSE LINUX Enterprise Server 9 和 Red Hat Enterprise Linux AS V3 或 V4。

本文內容包括:

  • 移植規(guī)劃
  • 開發(fā)環(huán)境(編譯器,make 工具,等等)
  • 依賴于體系架構或系統(tǒng)的區(qū)別

移植規(guī)劃
下面 6 個步驟為從 SPARC 平臺上的 Solaris 成功遷移到 x86 平臺上的 Linux 提供了一個完整的路線圖。如果您曾經將應用程序從一個操作系統(tǒng)移植到另外一個操作系統(tǒng)上,那么這些步驟可能就會聽起來非常熟悉:

  1. 準備
  2. 環(huán)境和 makefile 的變化
  3. 編譯器修正
  4. 測試和調試
  5. 性能優(yōu)化
  6. 打包并分發(fā)

步驟 1. 準備
正確準備的關鍵是了解某些領域之間的差異,例如:

  • 系統(tǒng)調用
  • 文件系統(tǒng)的支持
  • 依賴于機器的代碼
  • 線程
  • 內存映射
  • 系統(tǒng)調用
  • Endianness

在移植程序時,要確保有關的第三方包在目標平臺上都是可用的。對于 32 位的應用程序來說,要考慮是否有必要遷移到 64 位的版本。還要確定在目標平臺上使用哪種編譯器。在基于 x86 的 Linux 平臺上,可以使用 gcc 作為編譯器。

步驟 2. 環(huán)境和 makefile 的變化
在這個步驟中,您將設置開發(fā)環(huán)境,這包括確定環(huán)境變量,修改 makefile,并對環(huán)境進行必要的修改。在這個步驟之后,您應該準備好開始編譯自己的應用程序了。

在準備好進入下一個步驟之前,這個步驟可能會需要幾次反復。

步驟 3. 編譯
在這個步驟中,您將修正一些編譯錯誤,鏈接錯誤,諸如此類。在能夠得到一個干凈的編譯產品之前,這個步驟可能需要多次反復。

步驟 4. 測試和調試
在應用程序成功編譯之后,要對其進行測試,看看是否存在運行時錯誤。在測試時,有些領域可能會涉及客戶機/服務器的通信、數(shù)據交換格式、數(shù)據編碼的轉換(例如從單字節(jié)編碼轉換為多字節(jié)編碼)以及數(shù)據的永久保存。

步驟 5. 性能優(yōu)化
現(xiàn)在移植后的代碼可以在目標平臺上運行了。監(jiān)視其性能,確保所移植的代碼可以如我們所期望的一樣工作;如果不能,就需要對性能進行優(yōu)化。

有兩個很好的性能分析工具:Performance Inspector 和 OProfile。Performance Inspector 提供了一組工具來判斷 Linux 上的應用程序中的性能問題。從 2.6 版本的內核開始,OProfile 已經成為對代碼進行優(yōu)化分析的推薦工具。OProfile 在 RHEL4 中也可以使用。(有關這些工具的更多信息,請參閱 參考資料。)

步驟 6. 打包和分發(fā)
您要將所生成的代碼分發(fā)給其他人嗎?如果需要,就要確定打包的方法。

Linux 提供了幾種方法對應用程序進行打包,例如 tarball、自行安裝的 shell 腳本或 RPM。RPM 是 Linux 上廣泛使用的包管理系統(tǒng)。Solaris使用 pkgadmin 作為自己的包管理器。

在 Solaris 中,pkgadmin 所使用的包規(guī)范模板文件與 RPM 所使用的規(guī)范文件不同 —— 將打包信息從模板文件轉換成規(guī)范文件需要很多的努力。使用諸如 InstallShield for Multiplatforms(ISMP)之類的軟件包可以在這兩種平臺上產生通用的打包軟件,從而減少移植的努力。通過使用 ISMP,應用程序開發(fā)就可以使用一個跨平臺的通用規(guī)范文件。

開發(fā)環(huán)境
現(xiàn)在讓我們來看一下 Solaris 和 Linux 開發(fā)環(huán)境的一些差異,包括以下內容:

  • Makefile
  • 編譯器和鏈接選項
  • 32 位到 64 位的移植考慮

GNU Make 和 Solaris Make 的比較
如果您在原有的平臺上使用的是 Solaris 的 Make,那么要在 Linux 上使用 GNU Make,就需要對 makefile 進行修改。AIX 5L Porting Guide (請參閱 參考資料 中的鏈接)的第 6 章詳細介紹了二者之間的區(qū)別。

編譯器和鏈接選項
正如前面介紹的一樣,對 x86 上的 Linux 可用的編譯器是 GNU GCC。下表是 SUN Studio C/C++ 編譯器所廣泛使用的一些編譯選項,以及 GNU GCC 中的等價選項。

表 1. Solaris 到 Linux 的等價編譯器選項

SUN StudioGNU GCC說明
-#-v通知編譯器在編譯的過程中顯示信息。
-###-###跟蹤編譯過程,而不會真正調用任何操作。
-Bstatic-static讓鏈接編輯器只查找那些名為 libx.a 的文件。
-Bdynamic(缺省值)通知鏈接編輯器在給定 lx 選項時,首先查找名為 libx.so 的文件,然后查找名為 libx.a 的文件。
-G-shared產生一個共享對象,而不是一個動態(tài)鏈接的可執(zhí)行程序。
-xmemalign-malign-natural,指定假定內存邊界對齊的最大值,以及訪問不對齊的數(shù)據時的行為。
-xO1, -xO2, -xO3, -xO4, -xO5-O, -O2, -O3在編譯過程中選擇對代碼進行優(yōu)化的級別。有點類似于 O2。
-KPIC-fPIC生成位置無關的代碼,用于大型共享庫。
-Kpic-fpic生成位置無關的代碼,用于小型共享庫。
-mt-pthread為多線程代碼進行編譯和鏈接。
-R dirlist-Wl, -rpath, dirlist將動態(tài)鏈接庫的搜索路徑編譯到可執(zhí)行文件中。
-xarch-mcpu, -march指定目標體系架構的指令集。
操作系統(tǒng)內核級GCC 級Glibc 級Gnu binutils 級JDK 級
SLES92.63.3.32.3.32.15.901.4.2*
RHEL32.43.2.32.3.22.14.901.4.2
RHEL42.63.4.32.3.4-22.15.92.0.2-10.EL41.4.2*
Solaris 10Solaris 103.3.22.2.31.4.2
Linux(x86)Solaris(SPARC)
基本類型ILP32
(大。
(單位為字節(jié))
LP64
(用于基于 IA64
的系統(tǒng))
(大小)
(單位為字節(jié))
ILP32
(大。
(單位為字節(jié))
LP64
(大。
(單位為字節(jié))
char1111
short2222
Int4444
float4444
long4848
pointer4848
long long8888
double8888
long double12161616
數(shù)據類型Linux IA-32
(ILP32)
Linux IA-64
(LP64)
Bool11
Char11
wchar_t44
int44
Short22
long48
long long88
Float44
Double48
long double4*16
OSgid_tmode_tpid_tuid_twint_t
Solaris ILP32 llongunsigned longlonglonglong
Solaris LP64intunsigned intintintint
Linux ILP32unsigned intunsigned intintunsigned intunsigned int
Linux LP64unsigned intunsigned intintunsigned intunsigned int
int get_stack(void **StackPtr){  *StackPtr = 0;  __asm__ __volatile__ ("movl %%esp, %0": "=m" (StackPtr) ); return(0);}
        .section       ".text"        .align  8        .global my_stack        .type   my_stack,2my_stack:        ! Save stack pointer through 1st parameter        st      %sp,[%o0]        ! Compute size of frame in return result reg        retl        sub     %fp,%sp,%o0        .size  my_stack,(.-my_stack)
bool_t My_CompareAndSwap(IN int *ptr, IN int old, IN int new){        unsigned char ret;        /* Note that sete sets a 'byte' not the word */        __asm__ __volatile__ (                "  lock\n"                "  cmpxchgl %2,%1\n"                "  sete %0\n"                : "=q" (ret), "=m" (*ptr)                : "r" (new), "m" (*ptr), "a" (old)                : "memory");        return ret;}
        .section       ".text"        .align  8        .global        My_Ldstub        .type          My_Ldstub,2My_Ldstub:        ldstub         [%o0],%o0         ! Atomic load + set        sll            %o0,24,%o0        ! Zero fill ...        retl                             ! ... result register        srl            %o0,24,%o0        ! ... and retrn        .size          My_Ldstub,(.-My_Ldstub)
30931 pts/4    00:00:00 su31004 pts/4    00:00:00 ksh
struct sigaction  {    /* Signal handler.  */#ifdef __USE_POSIX199309    union      {        /* Used if SA_SIGINFO is not set.  */        __sighandler_t sa_handler;        /* Used if SA_SIGINFO is set.  */        void (*sa_sigaction) (int, siginfo_t *, void *);      }    __sigaction_handler;# define sa_handler     __sigaction_handler.sa_handler# define sa_sigaction   __sigaction_handler.sa_sigaction#else    __sighandler_t sa_handler;#endif    /* Additional set of signals to be blocked.  */    __sigset_t sa_mask;    /* Special flags.  */    int sa_flags;    /* Restore handler.  */    void (*sa_restorer) (void);  };
struct sigaction {        int sa_flags;        union {#ifdef  __cplusplus                void (*_handler)(int);#else                void (*_handler)();#endif#if defined(__EXTENSIONS__) || ((__STDC__ - 0 == 0) && \        !defined(_POSIX_C_SOURCE) && !defined(_XOPEN_SOURCE)) || \        (_POSIX_C_SOURCE > 2) || defined(_XPG4_2)                void (*_sigaction)(int, siginfo_t *, void *);#endif        }       _funcptr;        sigset_t sa_mask;#ifndef _LP64        int sa_resv[2];#endif};
  • 上一篇: 我的2.6.11內核編譯過程
  • 下一篇: Linux下添加硬盤,分區(qū),格式化詳解
  • 發(fā)表評論   告訴好友   打印此文  收藏此頁  關閉窗口  返回頂部
    熱點文章
     
    推薦文章
     
    相關文章
    網友評論:(只顯示最新5條。)
    關于我們 | 聯(lián)系我們 | 廣告合作 | 付款方式 | 使用幫助 | 機電之家 | 會員助手 | 免費鏈接

    點擊這里給我發(fā)消息66821730(技術支持)點擊這里給我發(fā)消息66821730(廣告投放) 點擊這里給我發(fā)消息41031197(編輯) 點擊這里給我發(fā)消息58733127(審核)
    本站提供的機電設備,機電供求等信息由機電企業(yè)自行提供,該企業(yè)負責信息內容的真實性、準確性和合法性。
    機電之家對此不承擔任何保證責任,有侵犯您利益的地方請聯(lián)系機電之家,機電之家將及時作出處理。
    Copyright 2007 機電之家 Inc All Rights Reserved.機電之家-由機電一體化網更名-聲明
    電話:0571-87774297 傳真:0571-87774298
    杭州濱興科技有限公司提供技術支持

    主辦:杭州市高新區(qū)(濱江)機電一體化學會
    中國行業(yè)電子商務100強網站

    網站經營許可證:浙B2-20080178-1