V rámci divočení se musí technologie prožít, ne pouze konzumovat. S příchodem nových silikonových Maců stejně jako jako před deseti lety taková divočina opět vypukne, protože nějaký blíže nejasný čas zas budou rovnocenné dvě různé architektury, přičemž ta nově stará bude mít ještě nějakou dobu hájení. Myslím, že je nejvyšší čas si to jít pořádně užít a prozkoumat to.
V minulém díle zbytečných nocí vyšlo tak nějak najevo, že Snow Leopard je nedostatečně univerzální. Byla to samozřejmě trochu nadsázka, protože pro dokonalou univerzálnost jsou potřeba dvě těžko oddělitelné věci, které ale Snow Leopard skutečně už neměl. Tou první je universal binary, což je vlastně jen poměrně jednoduché splácnutí několika samostatných binárek do jedné tlusté, tou druhou pak překladové prostředí, kterým je Rosetta, aby to mělo nějaký smysl. No a Big Sur tenhle smysl mít bude, pokud na ARMovém počítači spustí UB1, tedy pokud bude sestavena pro PowerPC a x86_64. Ale ehm, to se asi nestane. Nebo ano?
Aby bylo vůbec nějak možné si tohle začít zkoušet, chce to nejprve Big Sur a k němu nejnovější beta Xcode. Kupodivu je tohle jeden z těch složitějších kroků. Davídek na Granátovým jablku vždycky varuje, že používat betaverze software je pro odvážné školačky a že můžeme přijít o data. Jakoby jo, ale daleko jednodušší je postavit si nový virtuál a na něm zkoušet věci až do aleluja.
Přestože se dá někde obskurně sehnat přímo obraz s instalačkou Big Sur DP, úplně to pak v mnoha ohledech nefunguje dle požadovaných představ a je daleko lepší začít sice trochu pomaleji, ale s čistým štítem z čerstvé Cataliny. Tady hned z kraje upozorním, že virtuály ve výchozím nastavením s tímhle asi úplně nepočítají, takže co se týče tweaků, tak je v první řadě nutné zvýšit kapacitu virtuálního disku natolik, aby se to tam v první řadě po stažení vešlo (80-100 GB je optimální, možná až moc, ale 40 GB je rozhodně málo) a za další by se při instalaci Cataliny měl virtuální disk nově inicializovat s APFS, jinak to celé skončí v plamenech. K Big Suru pak už v novém systému vede cesta přes jeho zápis do Developer profilu, ovšem tohle v mnoha případech nefunguje pouze přes automatický balíček stahovatelný ze stránek pro vývojáře. Ať to zkrátím, na druhém snímku je to ručně vyvolané nástrojem seedutil ze Seedin frameworku, konkrétně jako seedutil enroll DeveloperSeed
(za předpokladu, že po zpackaném balíčku ještě proběhl unenroll
). Mám za to, že nefunkčnost způsobuje chybně specifikovaný program, ale kdo ví. No zkrátka, po úspěšném zápisu se v Software Update stažení Big Sur Beta objeví a na pár kliknutí zapracuje jako každý majoritní update.
Pak už stačí stáhnout zase z vývojářských stránek Xcode 12 beta a jeho příkazové nástroje pro UNIXovou ukázku a je to vlastně vybavené. Ačkoliv ano, něco selhat může, protože Xcode je poskytované v podepsaném .xib
balíčku, se kterým je optimální pracovat přímo v Big Suru někde, kde je dost místa a práv k zápisu, ale to z toho snad logicky vyplývá. Po zapnutí Xcode nabídne svoje rozhraní a v možnostech buildu i architektury, ale to není tak zábavné, jako na to jít v low-levelu, takže pro demonstraci univerzality tu budu zase ukazovat věci přímo v symbolických adresách a překládat je přiloženým assemblerem as
.
#include <stdio.h> int main() { printf("Eida.cz\n"); return 5; }
Nic lepšího mě nenapadlo, důležitý je hlavně návrat pětky, který byl dobře vidět v ukázce pro PowerPC, kde croissant možná nevědomky správně upozornila na ďábla v kódu, což je konstanta. Pro zajímavost je tady ale docela užitečný i printf do stdout, jelikož se použije už i nějaké skutečné systémové volání. Pro překlad do assembleru bude opět použit výchozí překladač (což je clang) s optimalizací -O2 a zákazem PIC, tj. clang
-S -O2 -fno-PIC
-arch {architektura}
peklo.c
-o peklo-{architektura}.s
. Když se to zavolá bez specifikace architektury, použije se nativní kód, což je v tuhle chvíli bohužel ještě ne ARM, ale x86_64.
.section __TEXT,__text,regular,pure_instructions .build_version macos, 10, 16 sdk_version 10, 16 .globl _main ## -- Begin function main .p2align 4, 0x90 _main: ## @main .cfi_startproc ## %bb.0: pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset %rbp, -16 movq %rsp, %rbp .cfi_def_cfa_register %rbp leaq L_str(%rip), %rdi callq _puts movl $5, %eax popq %rbp retq .cfi_endproc ## -- End function .section __TEXT,__cstring,cstring_literals L_str: ## @str .asciz "Eida.cz" .subsections_via_symbols
Pěkný. Je vidět, že je to čitelnější, nový překlad přidává do direktiv komentáře a celé je to docela povědomé a krásné. Bohužel když se specifikuje jiná architektura, třeba i386, už clang začne nadávat, že Unsupported architecture. Ono je to tím, že si sahá do výchozího systémového SDK, které je v /Library
a ne specificky v konkrétním Xcode. Takže tomu se dá pomoci explicitním vynucením konkrétního SDK v parametru -isysroot. SDK jsou v obsahu Xcode v substromu Developer/Platforms/
, konkrétně MacOSX.platform/Developer/SDKs
a výchozím aliasem MacOSX.sdk
. Pak už překlad po specifikaci architektury proběhne v pořádku, pro -arch i386
nic zásadního:
.section __TEXT,__text,regular,pure_instructions .build_version macos, 10, 16 sdk_version 11, 0 .globl _main ## -- Begin function main .p2align 4, 0x90 _main: ## @main .cfi_startproc ## %bb.0: pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset %ebp, -8 movl %esp, %ebp .cfi_def_cfa_register %ebp subl $8, %esp movl $L_str, (%esp) calll _puts movl $5, %eax addl $8, %esp popl %ebp retl .cfi_endproc ## -- End function .section __TEXT,__cstring,cstring_literals L_str: ## @str .asciz "Eida.cz" .subsections_via_symbols
Trochu mě překvapilo, že je 32bitové i386 pořád součástí, ale asi je to dáno tou určitou neoddělitelností od x86_64. Jako výše, nic překvapivého se tu nekoná, kód je jen lehce nostalgický a v komentáři pro SDK je už explicitně vidět změna z 10.16 na 11.0. No ale co už, přichází přece armagedon, ten musí být zajímavý! Navzdory tomu, že Linux označuje 64bitovou architekturu ARMu jako aarch64
, v macOS se jmenuje arm64
a úplně první kód bude vypadat následovně.
.section __TEXT,__text,regular,pure_instructions .build_version macos, 10, 16 sdk_version 11, 0 .globl _main ; -- Begin function main .p2align 2 _main: ; @main .cfi_startproc ; %bb.0: stp x29, x30, [sp, #-16]! ; 16-byte Folded Spill mov x29, sp .cfi_def_cfa w29, 16 .cfi_offset w30, -8 .cfi_offset w29, -16 Lloh0: adrp x0, l_str@PAGE Lloh1: add x0, x0, l_str@PAGEOFF bl _puts mov w0, #5 ldp x29, x30, [sp], #16 ; 16-byte Folded Reload ret .loh AdrpAdd Lloh0, Lloh1 .cfi_endproc ; -- End function .section __TEXT,__cstring,cstring_literals l_str: ; @str .asciz "Eida.cz" .subsections_via_symbols
Na první pohled je všechno v souladu s ARMovou ISA, všechny ty nové, neznámé a voňavé registry sedí a vypadá to fakt jako budoucnost. Teda asi. Je ale dost pravděpodobné, že takhle se v macOS nakonec programovat vůbec nebude, protože bezpečnost je na prvním místě a od roku 2016 je v platnosti specifikace pro armv8.3-A, kterou Apple adoptoval s procesory A12 a která zřejmě zcela jistě bude součástí macovských siliconů. Popravdě přináší krom jiného hlavně ověřování ukazatelů (PAC), což by mělo značně znepřítulnit útoky proti programům. To ještě uvidíme, důležité ale je, že je tato architektura zastoupena názvem arm64e
a je zřejmě praktickou budoucností.
.section __TEXT,__text,regular,pure_instructions .build_version macos, 10, 16 sdk_version 11, 0 .ptrauth_abi_version 0 .globl _main ; -- Begin function main .p2align 2 _main: ; @main .cfi_startproc ; %bb.0: pacibsp stp x29, x30, [sp, #-16]! ; 16-byte Folded Spill mov x29, sp .cfi_def_cfa w29, 16 .cfi_offset w30, -8 .cfi_offset w29, -16 Lloh0: adrp x0, l_str@PAGE Lloh1: add x0, x0, l_str@PAGEOFF bl _puts mov w0, #5 ldp x29, x30, [sp], #16 ; 16-byte Folded Reload retab .loh AdrpAdd Lloh0, Lloh1 .cfi_endproc ; -- End function .section __TEXT,__cstring,cstring_literals l_str: ; @str .asciz "Eida.cz" .subsections_via_symbols
Na první pohled je to dost podobné, ale přibyla tam právě specifikace ověřování ukazatelů v direktivě s verzí odpovídajícího ABI a pak přímo v programu jako pacibsp
, což přidává autentizační kód pro linkový registr x30
, který obsahuje návratovou adresu z funkce, s použitím kontextové hodnoty ukazatele na zásobník (sp
) pro podmíněný skok. Mělo by to tedy být celé v bezpečí.
Dobře, tak tohle jsou zatím po logické stránce čtyři architektury – dvě nově staré a dvě nově nové. No ale cílem dostatečně univerzální binárky je přece nadčasová zpětná podpora starých Maců s PowerPC. Jak na to? V první řadě jsou potřeba překladače, které ale nejsou součástí balení betaverze nového Xcode 12, takže musíme jít trochu zpátky v čase i v tomto ohledu a pokud paměť na Snow Leopard neklame, tyhle nástroje by měly být výborně k dispozici v soudobém Xcode 3.2, kde bude potřeba GCC zhruba verze 4.2. To je ke stažení zase z vývojářských stránek a stačí z toho vlastně vypreparovat jen systémové nástroje z /usr
.
Jenomže to nestačí. Staré nástroje na staré architektury nebudou schopny správně sestavit program proti SDK 11.0, kde se změnilo gorilion věcí. Kupodivu stačí pouze sehnat odpovídající SDK z dané doby – to je v tomhle případě asi nejlépe 10.4u – a pokusit se program sestavit proti nim, a to hezky na novém Big Suru. Ono si sice gcc-4.2 postěžuje, že couldn't understand kern.osversion 20.0.0, nicméně asemblerový kód a z něj odpovídající sestaví bez potíží jak pro ppc
, tak i pro ppc64
.
.machine ppc .cstring .align 2 LC0: .ascii "Eida.cz\0" .text .align 2 .p2align 4,,15 .globl _main _main: mflr r0 lis r3,ha16(LC0) la r3,lo16(LC0)(r3) stw r0,8(r1) stwu r1,-64(r1) bl _puts addi r1,r1,64 li r3,5 lwz r0,8(r1) mtlr r0 blr .subsections_via_symbols
Je trochu smutné, že ppc64
nakonec nebylo nikdy použito, ale za ten pocit, že můžeme architekturálně škálovat téměř do nekonečna, to stojí.
.machine ppc64 .cstring .align 3 LC0: .ascii "Eida.cz\0" .text .align 2 .p2align 4,,15 .globl _main _main: mflr r0 lis r3,ha16(LC0) la r3,lo16(LC0)(r3) std r0,16(r1) stdu r1,-112(r1) bl _puts addi r1,r1,112 li r3,5 ld r0,16(r1) mtlr r0 blr .subsections_via_symbols
Pokud už máme jednotlivé binárky, je posledním nutným krokem z nich už vyrobit pouze to poslední, tlustou binárku Universal Binary 2, což se dá dost jednoduše pomocí utility lipo. Utilitka možná doznala několika změn, které souvisely s přechodem 32bitových iOS na 64bitové, ale jinak se v ní nic moc nezměnilo a zkrátka stačí pomocí seznamu architektur s parametrem jednotlivých binárek vytvořit nový soubor.
% lipo -create -arch ppc peklo-ppc -arch ppc64 peklo-ppc64 -arch i386 peklo-i386 -arch x86_64 peklo-x86_64 -arch arm64 peklo-arm64 -arch arm64e peklo-arm64e -o peklo-all-ub2 % file peklo-all-ub2 peklo-all-ub2: Mach-O universal binary with 6 architectures: [ppc:Mach-O executable ppc] [ppc64:Mach-O executable ppc64] [i386:Mach-O executable i386] [x86_64:Mach-O 64-bit executable x86_64] [arm64:Mach-O 64-bit executable arm64] [arm64e:Mach-O 64-bit executable arm64e] peklo-all-ub2 (for architecture ppc): Mach-O executable ppc peklo-all-ub2 (for architecture ppc64): Mach-O executable ppc64 peklo-all-ub2 (for architecture i386): Mach-O executable i386 peklo-all-ub2 (for architecture x86_64): Mach-O 64-bit executable x86_64 peklo-all-ub2 (for architecture arm64): Mach-O 64-bit executable arm64 peklo-all-ub2 (for architecture arm64e): Mach-O 64-bit executable arm64e % hexdump peklo-all-ub2 | head 0000000 ca fe ba be 00 00 00 06 00 00 00 12 00 00 00 00 0000010 00 00 10 00 00 00 24 58 00 00 00 0c 01 00 00 12 0000020 00 00 00 00 00 00 40 00 00 00 22 48 00 00 00 0c 0000030 00 00 00 07 00 00 00 03 00 00 70 00 00 00 33 dc 0000040 00 00 00 0c 01 00 00 07 00 00 00 03 00 00 b0 00 0000050 00 00 31 10 00 00 00 0c 01 00 00 0c 00 00 00 00 0000060 00 01 00 00 00 00 c1 10 00 00 00 0e 01 00 00 0c 0000070 80 00 00 02 00 02 00 00 00 00 80 a8 00 00 00 0e 0000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 *
Signatura 0xcafebabe
je pro univerzálky zábavná. Systém by se měl po jejím otevření pokusit spustit v první řadě část pro svou nativní architekturu a pokud ji nenajde, tak tu, pro kterou má překladovou vrstvu. Bylo by hrozně zajímavé a hezké sledovat, jak se na ARMu pomocí Rosetty 2 otevře x86_64 kontext, který použije Rosettu 1 ke spuštění PowerPC kódu, ale samozřejmě by nemělo nic bránit ani přímému překladu z PowerPC na ARM – pokud by ho tedy někdo implementoval a dal nadšencům do krevního oběhu.
Dostatečně univerzální Big Sur výsledek tu dávám k dispozici, zkoumání zrovna této technologie je vždycky přínosné a důvod je zase jako vždycky jasný – protože proč ne. Samozřejmě dostatečná univerzálnost nepotrvá věčně, to až odejde podpora Rosetty 2 a ARMové Macy už nespustí staré modifikované překladače – tedy pokud si z oficiálních opensource zdrojů nepostavíme arm-nativní vlastní. Ale i tak, v daleké budoucnosti, už UB2 potřeba nebude a sny se rozplynou. Pokud tedy v roce 2030 nepřijde nový přechod na nový procesor a nové UB3 a nedokonale univerzální budoucí systémy.