Eida.cz - Dostatečně univerzální Big Sur

Dostatečně univerzální Big Sur

Eida

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.

Apple Silicon dočasně přinese novu éru Universal Binary 2

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.

peklo.c 68 bajtů
#include <stdio.h>

int main() {
	printf("Eida.cz\n");
	return 5;
}
Úplně jednoduchý příklad v C. Na rozdíl od minule se už ale použije printf ze stdio.h, tj. jaderné volání pro zápis do stdout.

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.

peklo-x86-64.s 632 bajtů
	.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
Symbolický kód pro x86_64.

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:

peklo-i386.s 656 bajtů
	.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
Symbolický kód pro i386. Žádná věda tady.

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

peklo-arm64.s 746 bajtů
	.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
Základní arm64 symbolický kód.

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

peklo-arm64e.s 781 bajtů
	.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
Symbolický kód pro arm64e. Specifikuje se ověřování ukazatelů.

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.

peklo-ppc.s 280 bajtů
	.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
Symbolický kód pro 32bitové PowerPC, ppc.

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

peklo-ppc64.s 285 bajtů
	.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
Symbolický kód pro 64bitové PowerPC, ppc64.

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
*
Sestavení a ověření výsledku – typ souboru, magická signatura 0xcafebabe.

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.

peklo-all-ub2160.16 KiB
Výsledná Universal Binary 2 binárka pro šest architektur.

PGP podpis pro zde přiloženou binárku.

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.

Tento článek přečetlo již 336 čtenářů (0 dnes).

Komentáře

Nový komentář