Několik tipů z konverze 32bit na 64bit

vložil Radek Voltr 5. ledna 2011 10:00

Zhruba před rokem a půl jsme řešili vzrůstající počet požadavků uživatelů na vylepšení podpory x64 platformy v naší aplikaci Spyware Terminator. Aplikace je z valné části napsána v Delphi (aktuálně 2007) a tak jsme museli řešit i konverzi systémové služby pro 64bit platformu

Vzhledem k tomu, že se jedná o security aplikaci jsme řešili jako primární problém především změny a úpravy v driveru. Windows na 64bit platformě nepovolují hookovaní systémových funkcí a tak je nutné všechny detekce řešit pomocí oficiálních notifikací.

Úpravy driveru se úspěšně povedly a tak se objevil další požadavek a to 64bit verze systémové služby která byla napsaná v Delphi 2007. O pár zkušeností z této konverze bych se rád podělil.

Upozornění : Zkušenosti jsou založeny na FPC verze 2.2.4. Verze 2.4.0 již má některé chyby opraveny. Stejné problémy však mohou postihovat i jiné zdrojové kódy a proto je publikuji.

Vzhledem k nedostupnosti řešení od EMB jsme použili open source projekt Lazarus s kompilátorem FPC. Lazarus jako IDE se ukázal dostatečně stabilní (ovšem do ideálu má ještě daleko) a použitelný pro vývoj.

Vzhledem ke struktuře aplikace jsme se rozhodli konvertovat pouze systémovou službu. Následující text proto neřeší konverzi VCL > LCL nebo podporu databází. Jako velká výhoda se také ukázalo použití vlastního Windows Services frameworku. Je založen na kódu z roku 1997 a úspěšně používán od NT 4. Jeho výhodou je především čistě API řešení bez VCL návaznosti a možnost spouštění služby v debug režimu v IDE. Kód obsahuje cca 40 tisíc řádků vlastního kódu (bez započítání systémových a 3rd party unit)

A ted zmíněných par tipů :

Neduplikujte si práci

FPC obsahuje poměrně dost různých unit a většina z nich je schopná korektně pracovat na všech platformách. Proveďte analýzu svého kódu a použijte FPC unity tam kde je to možné. V našem případě se jednalo např. o počítání MD5 a dalších pár drobností.

SizeOf(Integer)<>SizeOf(Pointer)

Nejzásadnější problém při konverzi z 32 na 64 bitů jsou jednoznačně délky proměnných. Jistě každý zná a používá konverzi Integer(pointer) a opačně. Na 64bit platformě je to ilegální protože pointer je 64bit ale Integer/Longint jsou pouze 32bit. Důsledky použití jsou vcelku jasné. Jako jistý "bonus" je následné chování debuggeru v případě této chyby. Většinou selže, ukáže neznámou vyjímku a není naplněn callstack. Proto se podobná konverze dost často stává příslovečnou jehlou v kupce kódu.

Windows obsahují typ LPTRINT který je v FPC pod jmenem "ptrint". Tento typ má délku 32/64bit podle cílové platformy a je proto bezpečný pro přetypování.

Jak postupovat při konverzi : 1. projít kód pomocí Find a najít potenciálně nebezpečná přetypování 2. sledovat warning kompilátoru "Warning: Conversion between ordinals and pointers is not portable" který tyto problémy identifikuje

Bohužel se vám může stát že toto nestačí. Kompilátor neukáže všechny přetypování a vy je také nenajdete. Zde je bohužel jen jedna rada - pomocí komentářů eliminujte části kódu a následně logujte průběh operací. A také není špatné se modlit :-) V mém případě se jednalo o místo volané threadem, spouštěným z jiného threadu na základě požadavku ze systémového driveru.

Pozor na to ze Handle je take 64bitová a proto je zde stejný problém.

Typy a jejich definice

V případě že používáte některé API funkce se můžete dostat do stavu kdy definice jednoho typu je v několika unitách. To samozřejmě není zásadní problém ale pouze pokud jsou všechny definice korektní.

FPC 2.2.4 obsahoval JCL unity s chybou kde LPTRINT byl definovan jako = longint. Na první pohled se pak kód jevil jako správný ale nefunkční. Až po delším zkoumání jsem zjistil že JCL používá vlastní definice které byly špatně. Současná veze JCL by již měla být opravena ale na podobný problém můžete narazit i v jiných knihovnách

Rekordy, struktury a jejich zarovnání

Těsně před koncem prací, v době kdy vše vypadalo krásně a funkčně jsme narazili na problém s jedním systémovým eventem. Služba jej vytvořila ale nebyla schopna mu změnit mandatory level. V důsledku toho se 32bit aplikace spouštěné uživatelem nebyly schopny na event připojit a synchronizovat se. Vzhledem k tomu že v debug mode se chyba neprojevuje (service v debugu i aplikace jedou na medium levelu) se problém detekoval relativně pozdě a od začátku nedával moc smysl.

Zkoumáním kódu jsme došli až na funkce pro manipulaci s ACE které vraceli chybu 87 - Invalid parameter. Bohužel tato informace je dost nepoužitelná protože neříká kde je problém. Následovala proto kontrola definice funkce, definice parametrů atd… ale vše se jevilo v pořádku. Protože možnosti byly vyčerpány provedl jsem test s Visual Studiem Express 2008 kde identický kód bez problému prošel. Při následném porovnání opět vypadalo vše stejně. Jako poslední nápad jsem zavolal sizeof na record a structuru a zjistil jsem zásadní rozdíl. Při dalším zkoumání jsem pak došel k tomu že FPC a VS zarovnávají položky v recordech/structurach ruzně.

Rešením pak bylo vložení direktivy {$PACKRECORDS C} která přikáže FPC použít GCC zarovnávání které je různé na různých platformách a korektní.

Službu jsme pak již doladili a tak již nějakou dobu podporujeme x64 verze Windows s plnou podporou realtime štítu stejně jako u 32bit. Části které jsou vizuální jsou dále 32bitové a se službou komunikují pomocí named pipes a to úplně bez problému.

Hodně štěstí při vašich konverzích a pevné nervy

Tagy:

Delphi | Jazyk | Nástroje | Praxe

Komentáře

5.1.2011 20:29:00 #

pingback

Pingback from topsy.com

Twitter Trackbacks for
        
        Delphi.cz | NÄ›kolik tipĹŻ z konverze 32bit na 64bit
        [delphi.cz]
        on Topsy.com

topsy.com

6.1.2011 19:38:14 #

pepak

Článek mě zaujal ze dvou důvodů:

1) Moje zkušenost s FreePascalem (asi před dvěma roky) je veskrze špatná, kompilátor i standardní knihovny mají naprosto nečekané chyby i v naprosto triviálních funkcích (Swap...), takže je pro mě velmi zajímavá informace, že v něm někdo úspěšně napsal podstatnou část hodně používané aplikace. Že by se FreePascal dostával do stavu, kdy začne mít smysl s ním počítat i jinak než jen jako s kuriozitou?

2) Netušil jsem, že FreePascalem jde už teď psát 64bitový kód. To je skutečně bomba, zvlášť s ohledu na projekt, na kterém momentálně pracuji - tam se mi to bude zatraceně hodit!

Vůbec bych nebyl proti, kdyby se tady na Delphi.cz objevilo pár článků o FreePascalu. Třeba by mě zajímala jeho podpora Unicode - co jsem zkoumal dokumentaci, tak to FreePascal umí, ale nepodařilo se mi najít, jestli se dá nějak "přepínat" mezi ANSI a Unicode (asi jako kdybych střídal Delphi 2007 a Delphi 2009).

pepak

6.1.2011 19:45:03 #

radekc

Nejsem si jist, zda to byla podstatna cast aplikace - spíše jen menší část. Navic mi neni jasne proc bylo nutno prepisovat sluzbu do 64bit, jelikoz Windows64 podporuji 32bit sluzby bez problemu.



radekc

6.1.2011 21:46:55 #

Radek Voltr

Ohledne rozsahu aplikace - do FPC jsme kod pouze portovali, napsan byl puvodne v Delphi 2007 (a pred tim v 7cce). Navic je situace takova ze driver je v C, sluzba pro 64bit je v FPC, sluzba pro 32bit je v Delphi a casti komunikujici s uzivatelem jsou taky v Delphi.

Takze se da rict ze vetsina aplikace je stale napsana v Delphi i kdyz na x64 windows neni jedna z dulezitych casti kompilovana Delphi kompilatorem.

Co se tyka FreePascalu - odhadem tak pred 14ti lety jsem v nem neco psal pro Linux a bylo to v pohode (jednalo se o specialni smtp/pop3 server), pak jsem si s nim hral na obskurnich zarizenich ala Nokia 770 (Internet tabletik s ARMem a linuxem) ale pro realne nasazenou vec jsme ho pouzili az ted. A bylo to relativne bez problemu

BTW : Prave portujeme jednu z nasich novych aplikaci na MacOS a vypada to ze slusna cast kodu pujde pouzit ale neco se bude muset napsat holt znova pro Mac API. Taky se pouziva FPC kompilator na kod puvodne v D2007


Co se tyka prepisu sluzby - duvody byly dva. Prvni je ten ze me osobne prijde zverstvo provozovat systemovou sluzbu v emulaci (a to i v pripade kdy emulace na x64 procesorech neni zasadne narocna a slape dobre). Druhou veci je to ze sluzba security aplikace potrebuje pristupy na vsechny lokace a je rozumnejsi pristupovat z 64bit kodu na veci ulozene pro 32bity nez presvedcovat API aby zpristupnilo prislusne 64bit lokace z 32bit kodu (coz ale pouzivame taky)

Pokud by ta sluzba delala neco jineho tak bych asi prepis neresil ale v tomdle pripade jsme se rozhodli to minimalne zkusit (a kupodivu se zadarilo)

Radek Voltr

Komentování ukončeno

Naše nabídka

MVP
Ing. Radek Červinka - Embarcadero MVP
profil na linkedin, Twitter:@delphicz

Nabízím placené poradenství a konzultace v oblasti programování a vývoje SW.
Dále nabízíme i vývoj speciálního software na zakázku.

Neváhejte nás kontaktovat (i ohledně reklamy).

love Delphi

O Delphi.cz

Delphi je moderní RAD nástroj podporující tvorbu nativních aplikací pro platformu Win32, Win64, Mac OSX, Linux a na iPhone a Android.

Delphi.cz je nezávislý portál pro uživatele Delphi. Portál není koncipován pro úplné začátečníky, i když i ti se zde nebudou nudit, ale spíše na programátory, kteří již něco znají a chtějí své znalosti dále rozvíjet a sledovat novinky.

Poslední komentáře

Comment RSS

Dle měsíců