Wydanie standardowej biblioteki C Cosmopolitan 2.0, opracowanej dla przenośnych plików wykonywalnych

Opublikowano wydanie projektu Cosmopolitan 2.0, rozwijającego standardową bibliotekę C i uniwersalny format plików wykonywalnych, za pomocą których można dystrybuować programy dla różnych systemów operacyjnych bez użycia interpreterów i maszyn wirtualnych. Wynik uzyskany przez kompilację w GCC i Clang jest kompilowany do statycznie połączonego uniwersalnego pliku wykonywalnego, który można uruchomić na dowolnej dystrybucji Linuksa, macOS, Windows, FreeBSD, OpenBSD, NetBSD, a nawet wywołać z BIOS-u. Kod projektu rozpowszechniany jest na licencji ISC (uproszczona wersja MIT/BSD).

Kontener do generowania uniwersalnych plików wykonywalnych opiera się na łączeniu w jednym pliku segmentów i nagłówków specyficznych dla różnych systemów operacyjnych (PE, ELF, MACHO, OPENBSD), łącząc w sobie kilka różnych formatów stosowanych w systemach Unix, Windows i macOS. Aby mieć pewność, że pojedynczy plik wykonywalny będzie działać w systemach Windows i Unix, sztuczka polega na zakodowaniu plików Windows PE jako skryptów powłoki, wykorzystując fakt, że powłoka Thompson Shell nie używa znacznika skryptu „#!”. Aby utworzyć programy zawierające kilka plików (łącząc wszystkie zasoby w jeden plik), obsługuje tworzenie pliku wykonywalnego w postaci specjalnie zaprojektowanego archiwum ZIP. Schemat proponowanego formatu (przykładowa aplikacja hello.com):

MZqFpD='SEKTOR ROZRUCHU BIOS-u' exec 7 $(polecenie -v $0) printf '\177ELF...LINKER-ENCODED-FREEBSD-HEADER' >&7 exec "$0" "$@" exec qemu-x86_64 "$0" "$ @" wyjście 1 TRYB RZECZYWISTY… SEGMENTY ELF… NOTATKA OPENBSD… NAGŁÓWKI MACHO… KOD I DANE… KATALOG ZIP…

Na początku pliku wskazana jest etykieta „MZqFpD”, która jest postrzegana jako nagłówek w formacie Windows PE. Ta sekwencja jest również dekodowana w instrukcji „pop %r10; jno 0x4a ; jo 0x4a”, a linia „\177ELF” do instrukcji „jg 0x47”, które służą do przekazywania do punktu wejścia. Systemy Unix uruchamiają kod powłoki, który używa polecenia exec, przekazując kod wykonywalny przez nienazwany potok. Ograniczeniem proponowanej metody jest możliwość działania w systemach operacyjnych typu Unix jedynie przy użyciu powłok obsługujących tryb zgodności z powłoką Thompson.

Wywołanie qemu-x86_64 zapewnia dodatkową przenośność i umożliwia działanie kodu skompilowanego dla architektury x86_64 na platformach innych niż x86, takich jak płyty Raspberry Pi i urządzenia Apple wyposażone w procesory ARM. Projekt można również wykorzystać do tworzenia samodzielnych aplikacji, które działają bez systemu operacyjnego (bare metal). W takich aplikacjach do pliku wykonywalnego dołączony jest program ładujący, a program działa jak startowy system operacyjny.

Opracowana w ramach projektu standardowa biblioteka C libc oferuje 2024 funkcje (w pierwszym wydaniu było ich około 1400). Pod względem wydajności Cosmopolitan działa równie szybko jak glibc i zauważalnie wyprzedza Musl i Newlib, pomimo faktu, że Cosmopolitan ma o rząd wielkości mniejszy rozmiar kodu niż glibc i w przybliżeniu odpowiada Musl i Newlib. Aby zoptymalizować często wywoływane funkcje takie jak memcpy i strlen, stosuje się dodatkowo technikę „spływania wydajności”, w której do wywołania funkcji wykorzystywane jest powiązanie makra, w którym kompilator jest informowany o rejestrach procesora biorących udział w wykonywaniu kodu proces, który umożliwia oszczędzanie zasobów podczas zapisywania stanu procesora poprzez zapisywanie tylko zmiennych rejestrów.

Wśród zmian w nowej wersji:

  • Zmieniono schemat dostępu do zasobów wewnętrznych w pliku zip (podczas otwierania plików używane są teraz zwykłe ścieżki /zip/... zamiast prefiksu zip:..). Podobnie, aby uzyskać dostęp do dysków w systemie Windows, można użyć ścieżek takich jak „/c/...” zamiast „C:/...”.
  • Zaproponowano nowy moduł ładujący APE (Actually Portable Executable), który definiuje format uniwersalnych plików wykonywalnych. Nowy moduł ładujący używa mmap do umieszczenia programu w pamięci i nie zmienia już zawartości w locie. W razie potrzeby uniwersalny plik wykonywalny można przekonwertować na zwykłe pliki wykonywalne powiązane z poszczególnymi platformami.
  • Na platformie Linux możliwe jest użycie modułu jądra binfmt_misc do uruchamiania programów APE. Należy zauważyć, że najszybszą metodą uruchamiania jest użycie binfmt_misc.
  • Dla systemu Linux zaproponowano implementację funkcjonalności wywołań systemowych zastaw() i odsłonięcie() opracowanych w ramach projektu OpenBSD. Dostępny jest interfejs API do korzystania z tych wywołań w programach w językach C, C++, Python i Redbean, a także narzędzie zastaw.com do izolowania dowolnych procesów.
  • W kompilacji zastosowano narzędzie Landlock Make — wersję GNU Make z bardziej rygorystycznym sprawdzaniem zależności i wykorzystaniem wywołania systemowego Landlock w celu odizolowania programu od reszty systemu i poprawy wydajności buforowania. Opcjonalnie zachowana jest możliwość budowania przy użyciu zwykłego GNU Make.
  • Zaimplementowano funkcje wielowątkowości - _spawn() i _join(), które stanowią uniwersalne powiązania z interfejsami API specyficznymi dla różnych systemów operacyjnych. Trwają także prace nad wdrożeniem obsługi wątków POSIX.
  • Możliwe jest użycie słowa kluczowego _Thread_local, aby użyć osobnej pamięci dla każdego wątku (TLS, Thread-Local Storage). Domyślnie środowisko wykonawcze C inicjuje protokół TLS dla głównego wątku, co spowodowało wzrost minimalnego rozmiaru pliku wykonywalnego z 12 KB do 16 KB.
  • Do plików wykonywalnych dodano obsługę parametrów „--ftrace” i „--strace”, aby wyświetlać informacje o wszystkich wywołaniach funkcji i wywołaniach systemowych na stderr.
  • Dodano obsługę wywołania systemowego closefrom(), obsługiwanego w systemach Linux 5.9+, FreeBSD 8+ i OpenBSD.
  • Na platformie Linux wydajność wywołań clock_gettime i gettimeofday została zwiększona aż 10-krotnie poprzez zastosowanie mechanizmu vDSO (virtual dynamic Shared Object), który umożliwia przeniesienie obsługi wywołań systemowych do przestrzeni użytkownika i uniknięcie przełączania kontekstu.
  • Funkcje matematyczne do pracy z liczbami zespolonymi zostały przeniesione z biblioteki Musl. Przyspieszono pracę wielu funkcji matematycznych.
  • Zaproponowano funkcję nointernet() w celu wyłączenia możliwości sieci.
  • Dodano nowe funkcje umożliwiające efektywne dołączanie ciągów znaków: appendd, appendf, appendr, appends, appendw, appendz, kappendf, kvappendf i vappendf.
  • Dodano chronioną wersję rodziny funkcji kprintf(), zaprojektowaną do pracy z podwyższonymi uprawnieniami.
  • Znacząco poprawiona wydajność implementacji SSL, SHA, curve25519 i RSA.

Źródło: opennet.ru

Dodaj komentarz