Opublikowano wydanie projektu Cosmopolitan 2.0, rozwijającego standardową bibliotekę C i uniwersalny format plików wykonywalnych, który można wykorzystać do dystrybucji programów dla różnych systemów operacyjnych bez użycia interpreterów i maszyn wirtualnych. Wynik uzyskany dzięki kompilacji w GCC i Clang jest łączony w statycznie łączony uniwersalny plik wykonywalny, który nadaje się do uruchomienia w dowolnej dystrybucji Linux, macOS, Windows, FreeBSD, OpenBSD, NetBSD, a nawet można go wywołać z BIOS-u. Kod projektu jest dystrybuowany na licencji ISC (uproszczona wersja MIT/BSD).
Kontener do formowania uniwersalnych plików wykonywalnych oparty jest na łączeniu segmentów i nagłówków specyficznych dla różnych systemów operacyjnych (PE, ELF, MACHO, OPENBSD) w jednym pliku, łącząc w nim kilka różnych formatów używanych w Unix, Windows i macOS. Aby zapewnić uruchomienie jednego pliku wykonywalnego w systemach Windows i Unix, stosuje się trik polegający na kodowaniu plików Windows PE w formie skryptu powłoki, wykorzystując fakt, że powłoka Thompsona nie używa znacznika skryptu „#!”. Dla tworzenia programów zawierających wiele plików (łączenie wszystkich zasobów w jeden plik) wspiera się formowanie pliku wykonywalnego w postaci specjalnie sformatowanego archiwum ZIP. Schemat proponowanego formatu (przykład aplikacji hello.com):
MZqFpD=’ BIOS BOOT SECTOR’ exec 7 $(command -v $0) printf ‘\177ELF…LINKER-ENCODED-FREEBSD-HEADER’ >&7 exec «$0» «$@» exec qemu-x86_64 «$0» «$@» exit 1 REAL MODE… ELF SEGMENTS… OPENBSD NOTE… MACHO HEADERS… CODE AND DATA… ZIP DIRECTORY…
Na początku pliku wskazany jest znacznik „MZqFpD”, który jest postrzegany jako nagłówek formatu Windows PE. Ta sekwencja jest także dekodowana w instrukcji „pop %r10 ; jno 0x4a ; jo 0x4a”, a ciąg „\177ELF” w instrukcję „jg 0x47”, które są stosowane do przerzutu na punkt wejścia. W systemach Unix wykonywany jest kod powłoki, w którym używana jest komenda exec z przekazaniem wykonywanego kodu przez kanał anonimowy. Ograniczeniem proponowanej metody jest możliwość uruchamiania w systemach Unix-podobnych tylko przy użyciu powłok wspierających tryb zgodności z powłoką Thompson.
Wywołanie qemu-x86_64 jest przewidziane do realizacji dodatkowej przenośności i pozwala na uruchomienie skompilowanego kodu dla architektury x86_64 na platformach innych niż x86, takich jak płyty Raspberry Pi i urządzenia Apple z procesorami ARM. Projekt może być również używany do tworzenia autonomicznych aplikacji działających bez systemu operacyjnego (bare metal). W takich aplikacjach do pliku wykonywalnego dołączany jest loader, a program działa jako ładowany system operacyjny.
W rozwijanej standardowej bibliotece C libc projekt przewiduje 2024 funkcje (w pierwszym wydaniu było około 1400 funkcji). W wydajności Cosmopolitan działa tak szybko jak glibc i wyraźnie wyprzedza Musl i Newlib, mimo że Cosmopolitan jest rozmiarem kodu o rząd wielkości mniejszy niż glibc i mniej więcej odpowiada Musl i Newlib. W celu optymalizacji często wywoływanych funkcji, takich jak memcpy i strlen, zastosowano technikę „trickle-down performance”, polegającą na tym, że do wywołania funkcji używany jest makro-obiekt, w którym kompilator jest informowany o rejestrach CPU, co pozwala na oszczędność zasobów przy zachowaniu stanu CPU przez zapisanie tylko zmieniających się rejestrów.
Wśród zmian w nowej wersji:
- Zmodyfikowano schemat odwołań do wewnętrznych zasobów w pliku zip (po otwarciu plików używane są teraz zwykłe ścieżki /zip/... zamiast odwołań z prefiksem zip:..). Podobnie, dla dostępu do dysków w Windows wprowadzono możliwość korzystania z ścieżek w postaci „/c/... ” zamiast „C:/...”.
- Zaproponowano nowy loader APE (Actually Portable Executable), który definiuje format uniwersalnych plików wykonywalnych. Nowy loader wykorzystuje mmap do umieszczania programu w pamięci i nie modyfikuje zawartości w locie. W razie potrzeby uniwersalny plik wykonywalny może zostać przekonwertowany na zwykłe pliki wykonywalne związane z określonymi platformami.
- Na platformie Linux wdrożono możliwość użycia modułu jądra binfmt_misc do uruchamiania programów APE. Zauważono, że użycie binfmt_misc jest najszybszą metodą uruchamiania.
- Dla systemów Linux wprowadzono implementację funkcji wywołań systemowych pledge() i unveil(), rozwijanych przez projekt OpenBSD. Udostępniono API do wykorzystania tych wywołań w programach napisanych w językach C, C++, Python oraz Redbean, a także narzędzie pledge.com do izolacji dowolnych procesów.
- Do kompilacji użyto narzędzia Landlock Make — wersji GNU Make z surowszym sprawdzaniem zależności oraz wykorzystaniem wywołania systemowego Landlock do izolacji programu od reszty systemu i zwiększenia efektywności cache'owania. Jako opcję zachowano możliwość kompilacji również za pomocą standardowego GNU Make.
- Wprowadzono funkcje dla programowania wielowątkowego — _spawn() i _join(), które stanowią uniwersalne związki nad specyficznymi dla różnych systemów operacyjnych API. Trwają również prace nad wprowadzeniem wsparcia dla wątków POSIX.
- Udostępniono możliwość korzystania z kluczowego słowa _Thread_local do użycia oddzielnych dla każdego wątku magazynów (TLS, Thread-Local Storage). Domyślnie czas uruchamiania C inicjalizuje TLS dla głównego wątku, co spowodowało wzrost minimalnego rozmiaru pliku wykonywalnego z 12 do 16 KB.
- Do plików wykonywalnych dodano wsparcie dla opcji „—ftrace” i „—strace” do wyświetlania w stderr informacji o wszystkich wywołaniach funkcji i wywołaniach systemowych.
- Dodano wsparcie dla wywołania systemowego closefrom(), wspieranego w Linux 5.9+, FreeBSD 8+ i OpenBSD.
- Na platformie Linux do 10 razy zwiększono wydajność wywołań clock_gettime i gettimeofday dzięki zastosowaniu mechanizmu vDSO (virtual dynamic shared object), który umożliwia przeniesienie obsługi wywołania systemowego do przestrzeni użytkownika i unikanie przełączania kontekstu.
- Z biblioteki Musl przeniesiono funkcje matematyczne do pracy z liczbami zespolonymi. Przyspieszono działanie wielu funkcji matematycznych.
- Proponowana jest funkcja nointernet(), która wyłącza możliwości sieciowe.
- Dodano nowe funkcje do efektywnego dołączania łańcuchów: appendd, appendf, appendr, appends, appendw, appendz, kappendf, kvappendf oraz vappendf.
- Dodano zabezpieczoną wersję rodziny funkcji kprintf(), przeznaczoną do działania przy podwyższonych uprawnieniach.
- Znacznie zwiększono wydajność realizacji SSL, SHA, curve25519 i RSA.
Źródło: opennet.ru
