32位程式移植到64位平台前的準備工作

2021-06-07 00:12:11 字數 4044 閱讀 9385

32位程式移植到64位平台前的準備工作

2006-02-13 09:18:46     

我來說兩句 

收藏   

我要投稿    [字型:

小大]

我們最近完成的乙個專案是移植乙個大型的32位應用程式,它可在64位環境中支援11個作業系統平台,並且程式的源**超過了30萬行。由於此32位程式是在幾年前分成幾部分開發而成,所以極有可能**是由不同的開發者編寫。鑑於此,我們有理由懷疑,在64位移植中導致問題的型別不匹配,很有可能是在這幾年中隨著程式模組的新增與刪除而引入的。

我們移植此32位程式到64位平台,是為了利用64位技術的先進之處--支援更大的檔案、支援更大的記憶體、及64位計算,大體使用的方法是乙個反覆迭代的過程,不斷地在一些細節問題上來來回回,如位元組序、調整編譯器選項等等,並時不時停下來檢視是否達到了總體目標--遵從ansi標準及源**將來的可移植性。第一步,我們研究了64位的系統資源,以充分了解11個作業系統平台上每乙個的編譯器選項、記憶體模型和編碼方面的考慮。作為全部工作的起點,我們在其中乙個平台上開啟了所有編譯器警告,進行第一次構建,並仔細檢查構建日誌資訊。通過這些最初的構建、使用本地偵錯程式、及之後使用如parasofts insure++ (這樣的工具,我們確定了乙個開發藍圖,接下來,編制了乙個清晰徹底的源**目錄清單,並在每次配置構建之後進行相應的檢查。

經過最初的**修改、除錯、查閱構建日誌,已經有足夠的資訊對現實中可能碰到的事件進行排序以確定優先次序。在乙個擁有所有基本功能的程式成功地通過我們的自動測試案例之後,移植工作總算到了乙個轉折點;此測試除了測試64位功能,也包含了向後相容性測試。如果你所移植的專案中有幾個不同的64位平台,很可能要在其上一一測試,一旦程式可在第乙個平台上正確執行,接下來就要測試下乙個平台,如此這般下去。然而,我們卻發現了乙個非常好的方法,可在同一時間,在所有的平台上進行工作,這是因為:

·每乙個編譯器都在它的警告資訊中都提供了不同的資訊,仔細檢視幾個編譯器產生的錯誤,可有助於我們定位問題區域。

·不同平台上,錯誤也不同。同乙個問題,在另乙個平台上看上去無任何跡象,很可能會在當前平台上導致程式崩潰。

在此專案中,最後需要考慮的一點是為最終發布的測試階段作提前計畫。因為最近修改的**會被32位及64位的多平台共享,所以在每乙個32位平台上,必須重新進行徹底地測試,這要花上雙倍的測試時間和資源。

跨平台問題

某些應用程式需要訪問那些64位與32位共享的二進位制資料或檔案,在這種情況下,必須仔細檢查long與指標的二進位制格式,可能需要修改相關的讀寫函式以轉換不同的大小,並在多平台間處理大字節序與小字節序問題。為得到正確的機器字節序,在64位程式中更大的資料尺寸需要更多的位元組交換。

例如,乙個32位的long:

big endian(大字節序)= (b0, b1, b2, b3)

轉換為:

little endian(小字節序)= (b3, b2, b1, b0)

而乙個64位的long:

big endian(大字節序)= (b0, b1, b2, b3, b4, b5, b6, b7) 

轉換為:

little endian(小字節序)= (b7, b6, b5, b4, b3, b2, b1, b0)

大多數的編譯器能發現型別的不匹配,並能在構建期間糾正它們,這對如傳遞給函式的引數這樣大多數的簡單賦值來說是正確的。而真正的問題在於,對int、long、指標之間的不匹配,編譯器在編譯期間卻視而不見,或者說編譯器在編譯期間所做的假設,導致了這種不匹配問題依然存在。前者涉及指標引數及函式指標,而後者主要是有關於函式原型。

傳遞乙個int和long指標作為函式引數時,如果這個指標之後被解引用為乙個不同的、不相容的型別,也會導致問題。這種情況不是32位**的問題,而是因為ing與long是不可互換的。但是,在64位**中,卻因為指標與生具有的可伸縮性,這種情況將導致執行時錯誤,大多數編譯器假定你正在做的事情,就是你想要做的事情,所以會悄無聲息地對此問題放行,除非開啟更多的警告資訊。而通常只有在程式執行時,此問題才會浮出水面。

舉例來說,例1可同時在solaris和aix(frote7、vac 6)的32位與64位模式中通過編譯,而沒有任何警告,然而,64位的版本執行時卻輸出不正確的值。在如此短的示例中,這種問題很容易被發現,如果在更大型的**中呢,恐怕會難多了吧。這種型別的問題可隱藏在現實中實際的**裡,而大多數的編譯器卻不能發現它們。

例1:#include

#include

int func1(char *);

int main()

int func1(char * input)

當作為64位可執行程式執行於小字節序機器上時,例1顯得一切正常,因為arg的值完全包含在long的四個最少有意義的位元組中。然而,甚至在小字節序的x86機器上,當arg的值超出了四個最少有意義的位元組時,64位的版本也會在執行期間產生乙個錯誤。

正是因為函式指標,編譯器無法獲取資訊,以確定哪乙個函式將會呼叫,因此它不能糾正或警告你有關可能存在的型別不匹配問題,所有通過特定函式指標呼叫的函式引數與返回型別都在此範圍之內。如果想從根本上糾正此問題,你必須提供一種分離的方案,在函式呼叫時對引數及返回值進行適當的型別轉換。

第二個問題涉及隱式函式宣告,如果沒有對**中呼叫的每乙個函式提供乙個原型,編譯器就會做出假設。編譯器產生的類似警告資訊"implicit function declaration: assuming extern returning int"在32位構建時通常是無關緊要的;但在64位構建時,這種返回值是int的假設,當函式實際上是返回long或指標(例如malloc)時,就會導致真正的問題了。為了不讓編譯器做出這種假設,必須確保所有需要的系統標頭檔案都包含或提供了外部函式的函式原型。

隱藏的問題

當然,也有一些問題不會在一開始就很容易地被發現,例如,在64位程式中,long與指標尺寸更大了,隨之也會帶來包含它們的結構大小上的增長。結構元素的排列方式決定了結構將占用多大的空間,舉例來說,乙個包含了int其後跟著乙個long的結構,在32位程式中占用8位元組,但64位程式在結構的第乙個元素上加入了4個位元組的填充資料,以使第二個元素在邊界上排列得更自然,見圖1:

圖1:32位與64位結構中資料的排列方式

為最小化填充資料所帶來的影響,可把結構中的資料元素按從大到小重新排列。但是,如果資料元素是通過位元組流訪問的,還必須調整**中的邏輯部分,以適應結構中的新的資料排列方式。

在那些重新排列結構資料不起作用,或資料元素是通過位元組流訪問的情況中,就要小心計算填充資料,我們對此的解決方案是,實現乙個幫助函式,在把資料寫到位元組流之前,從結構中消去多餘的填充資料;而由此帶來的另乙個好處是,在讀取資料時就不需要作任何修改了,參見例2:

例2:typdef struct demo demo;

demo test;

/*pout_raw輸出原始資料到乙個檔案中*/

/*輸出結構的每乙個元素並避免了填充資料*/ 

pout_raw ((int) file_unit, (char *) test.i, sizeof (test.i)); 

pout_raw ((int) file_unit, (char *) test.j, sizeof (test.j));

/*下行包含了填充資料*/ 

pout_raw ((int) file_unit, (char *) test,sizeof(test));

陣列問題

64位上的long型陣列或結構中的陣列,不只是比它們32位的對等體包含更大的數值,而且可包含更多的元素。回頭看一下前面用來定義陣列邊界和分配陣列大小的4位元組變數,它們可被轉換成long。如果為了讓64程式獲得更好的效能,需決定現存的long陣列是否應轉換成int型別,請參考

編碼慣例與移植考慮

除了遵循作業系統編譯器文件所推薦的標準64位編碼慣例之外,以下還有一些意見及小提示,也許在計畫向64位移植時,可幫得上忙:

·如果可能且現實,把源**轉換為ansi c/c++。這將簡化64位移植過程,甚至將來的移植也會受益。

·你的目標作業系統同時支援32位與64位應用程式嗎?應及早知道答案,因為它會對是否移植產生影響。例如:在solaris上,使用系統命令isainfo檢查32位與64位程式的相容性。

·如果你的源**已經被如cvs之類的版本控制系統管理,在移植之前,將

64位平台轉32位平台總結

一般都是32位平台轉到64位平台,可是我們剛好相。我們公司最近做的分布式檔案系統,以前是在 64位平台下 以為現在的伺服器很少有 32位平台,也就沒有過多的考慮,現在由於客戶需要,不得不修改至 32位平台。現在總結如下,共大家學習。1 資料型別的定義 一般我們都用 typedef 定義資料型別 ty...

32位程式移植到64位需要考慮的問題

翻譯自 概述 從32位到64位,根本性的區別在於兩種資料型別發生了變化 long和pointer。在32位環境下,顧名思義,兩者長度都是32位,也就是4個位元組 而在64位環境下,都是8個位元組。所以,當你把pointer或者long型資料賦給int型時,會發生資料截斷 data truncatio...

linux64位平台移植

linux64 最大好處就是記憶體不在有 4gb的限制 32位 linux 只有4g 的虛擬位址定址空間,可以克服這個限制,但是實現起來會比較複雜,得不償失 資料模型 ilp32 lp64 llp64 ilp64 char 8 8 88 short 16 16 16 16int 32 32 32 6...