Dlaczego numery systemowe w Linuksie w wersjach x86 i x86_64 są różne?


35

Wiem, że interfejs wywołania systemowego jest implementowany na niskim poziomie, a zatem zależy od architektury / platformy, a nie „ogólnego” kodu.

Jednak nie widzę jasno, dlaczego wywołania systemowe w Linuksie 32-bitowe jądra x86 mają numery, które nie są takie same w podobnej architekturze Linux 64-bit x86_64? Jaka jest motywacja / powód tej decyzji?

Moje pierwsze przypuszczenie polega na tym, że przyczyną tła było utrzymywanie działania aplikacji 32-bitowych w systemie x86_64, aby dzięki rozsądnemu przesunięciu w stosunku do numeru wywołania systemowego system wiedział, że przestrzeń użytkownika jest 32-bitowa lub 64-bitowa odpowiednio. Tak jednak nie jest. Przynajmniej wydaje mi się, że read () będący wywołaniem systemowym o numerze 0 w x86_64 nie może być dopasowany do tej myśli.

Innym przypuszczeniem jest to, że zmiana numerów wywołań systemowych może mieć podłoże zabezpieczające / hartujące, czego nie byłem w stanie potwierdzić.

Nie znając wyzwań związanych z implementacją części kodu zależnych od architektury, wciąż zastanawiam się, jak zmienić systemowe numery wywoławcze , kiedy wydaje się, że nie ma takiej potrzeby (ponieważ nawet 16-bitowy rejestr przechowałby znacznie więcej niż obecnie ~ 346 liczb do reprezentowania wszystkich wywołania), pomogłyby w osiągnięciu czegokolwiek, poza zerwaniem kompatybilności (chociaż używanie wywołań systemowych przez bibliotekę, libc, łagodzi to).


3
Myślę, że zadajesz złe pytanie. Prawidłowe pytanie brzmi: dlaczego należy zachować je tak samo: zgodność odpowiedzi. Jeśli więc x86 i x86_64 są niekompatybilne, nie ma żadnych sił, które powstrzymałyby je przed zmianą. Teraz wszystkie siły z ostatnich 20 lat, które chciały zmiany, będą dominować (mamy szansę je zmienić). [Zwróć uwagę, że to tylko opinia i nie opiera się ona na wewnętrznym umyśle projektantów nowego systemu.]
ctrl-alt-delor

Odpowiedzi:


34

Jeśli chodzi o uzasadnienie konkretnej numeracji, która nie pasuje do żadnej innej architektury [z wyjątkiem „x32”, która jest tak naprawdę tylko częścią architektury x86_64]: W pierwszych dniach obsługi x86_64 w jądrze Linuksa, zanim pojawiły się jakieś poważne ograniczenia kompatybilności wstecznej, wszystkie połączenia systemowe zostały ponumerowane, aby zoptymalizować je na poziomie użycia pamięci podręcznej .

Nie wiem wystarczająco dużo na temat rozwoju jądra, aby poznać konkretną podstawę tych wyborów, ale najwyraźniej istnieje pewna logika przy zmianie numeracji wszystkiego za pomocą tych konkretnych liczb zamiast po prostu kopiowania listy z istniejącej architektury i usuwania nieużywanych. Wygląda na to, że kolejność może zależeć od tego, jak często się je nazywa - np. Odczyt / zapis / otwarcie / zamknięcie są z góry. Wyjście i rozwidlenie mogą wydawać się „fundamentalne”, ale każde z nich wywoływane jest tylko raz na proces.

Może się również zdarzyć coś z utrzymywaniem wywołań systemowych, które są często używane razem w tej samej linii pamięci podręcznej (te wartości są tylko liczbami całkowitymi, ale w jądrze znajduje się tabela z wskaźnikami funkcji dla każdego z nich, więc każda grupa 8 wywołań systemowych jest zajęta 64-bajtowa linia pamięci podręcznej dla tej tabeli)


1
fork may seem "fundamental", but [...] called only once per process.Oh, co? Rozumiem, można oczekiwać, aby zadzwonić zjazd raz, ale można wybulić wewnątrz rodzica i dziecko fork()połączeń
kot

5
@cat, jeśli widzisz, że forkjest rozliczany w procesie potomnym (tzn. widzisz go jako wywołanie tworzenia procesu), a nie w procesie nadrzędnym, to instrukcja Random832 jest poprawna.
icarus

4
@cat OK, możesz wywołać fork () dwa lub trzy razy, może jeszcze kilka. Ale możesz nazywać read () miliony, a nawet miliardy razy.
Michael Hampton,

1
Tak właśnie miałem na myśli. Liczba wywołań rozwidlenia i liczba procesów w całym okresie istnienia systemu będą identyczne, ignorując szczegóły takie jak init, klon [który może tworzyć procesy lub wątki] itp.
Random832

15

Zobacz tę odpowiedź na pytanie „Dlaczego numery wywołań systemowych różnią się w Linuksie amd64?” na przepełnienie stosu.

Podsumowując: ze względu na kompatybilność lista wywołań systemowych jest stabilna i może się powiększać. Kiedy pojawiła się architektura x86 64, ABI (przekazywanie argumentów, zwracana wartość) było inne, dlatego twórcy jądra skorzystali z okazji, aby wprowadzić zmiany, na które długo czekał.


Fajnie, moje przypuszczenie było słuszne.
ctrl-alt-delor

2
Ta inna odpowiedź, do której linkujesz, jest spekulatywna: mówi „Linux faceci najprawdopodobniej zdecydowali ...” (podkreślenie dodane). Myślę, że pomogłoby to, gdyby twoja odpowiedź tutaj zawierała pewne wskazówki, że najwyraźniej opiera się ona raczej na spekulacjach niż dowodach. Nawiasem mówiąc, nowszy komentarz opublikowany pod połączoną odpowiedzią dostarcza dowodów, że prawdziwym powodem nie jest ogólne czyszczenie cruft (jak spekuluje ta odpowiedź), ale konkretnie dotyczy „użycia pamięci podręcznej”, jak wyjaśniono w innej odpowiedzi tutaj .
DW

-3

Krótko mówiąc, ponieważ ktoś pomyślał, że „ N+1nieuzasadnione niezgodne sposoby są lepsze niż Nsposoby”. W przypadku historycznych łuków numery syscall były zwykle wybierane, aby pasowały do ​​niektórych starszych zastrzeżonych systemów uniksowych. Ale dla x86_64 programiści jądra mogli dowolnie wybierać dowolną numerację. Zamiast dokonać prostego wyboru i ponownie wykorzystać istniejącą numerację, wybrali nowy standard. Potem zrobili to ponownie dla aarch64 i kilku innych. Jest to często powtarzany wzorzec w rozwoju jądra Linuksa.


3
Zmiana nie była nieuzasadniona. Istnieją solidne powody techniczne. Gdyby nie wymagania kompatybilności wstecznej, podobne zmiany zostałyby również zastosowane w istniejących architekturach.
Jörg W Mittag,

Różnica w numeracji jest w 100% bezpłatna. Żadna konkretna numeracja nie ma przewagi technicznej.
R ..

2
Jak wyjaśnia ta inna odpowiedź , wywołania systemowe są pogrupowane w taki sposób, że powszechnie używane razem wywołania systemowe mają tę samą linię podręczną w tabeli wywołań. Liczby systemowe są wybierane w taki sposób, aby były prostymi wskaźnikami do tej tabeli. Teoretycznie moglibyśmy użyć warstwy pośredniej, aby oddzielić pozycję wywołania syscall w tabeli syscall od numeru syscall, ale prawdopodobnie pochłonęłoby to część wzrostu wydajności, jaki uzyskamy z umieszczenia gorących wywołań syscall w tej samej pamięci podręcznej.
Jörg W Mittag,

@ JörgWMittag: I to oczywiście przedwczesna optymalizacja, a nie wymierna poprawa. Wystarczy spojrzeć na liczbę cykli wywoływanych przez systemy i liczbę eksmitowanych linii pamięci podręcznej. Zapisanie co najwyżej jednej linii pamięci podręcznej z porządku tabeli nie ma znaczenia.
R ..

2
@R .. „Wybrałem numerację w funkcji informacji o profilowaniu jądra tpcc za pomocą popularnego DBMS i danych wyjściowych strace niektórych aplikacji sieciowych i stacjonarnych.” na pewno brzmi, jakby były pomiary. Jednak autor nie podał żadnych liczb lub odpowiednio wyjaśnił metodologię.
user45891,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.