|
1375 | 1375 | \pdfbookmark[1]{API/ABI}{APIABI}
|
1376 | 1376 |
|
1377 | 1377 | \begin{slide}
|
1378 |
| -\sltitle{API versus ABI} |
| 1378 | +\sltitle{API vs ABI} |
1379 | 1379 |
|
1380 | 1380 | API -- Application Programming Interface
|
1381 | 1381 |
|
1382 | 1382 | \begin{itemize}
|
1383 |
| -\item rozhraní pou¾ité pouze ve zdrojovém kódu |
1384 |
| -\item rozhraní \emsl{zdrojáku} vùèi systému, knihovnì èi vlastnímu kódu, tj. |
1385 |
| -napø. \texttt{exit(1)}, \texttt{printf("hello\bs{}n")} nebo |
1386 |
| -\texttt{my\_function(1, 2)} |
1387 |
| -\item \dots{}aby se stejný \emsl{zdrojový kód} mohl pøelo¾it na v¹ech |
1388 |
| -systémech podporující dané API |
| 1383 | +\item interface used in the \emsl{source code} to use another software |
| 1384 | +component like a library, OS kernel, or your own code -- eg. |
| 1385 | +\texttt{exit(1)}, \texttt{printf("hello\bs{}n")} or \texttt{my\_function(1, |
| 1386 | +2)} |
| 1387 | +\item \dots{}so that the same source code could be compiled on all systems |
| 1388 | +supporting a given API |
1389 | 1389 | \end{itemize}
|
1390 | 1390 |
|
1391 | 1391 | ABI -- Application Binary Interface
|
1392 | 1392 |
|
1393 | 1393 | \begin{itemize}
|
1394 |
| -\item low-level rozhraní \emsl{aplikace} vùèi systému, knihovnì èi jiné èásti |
1395 |
| -sama sebe |
1396 |
| -\item \dots{}aby se \emsl{objektový modul} mohl pou¾ít v¹ude tam, kde |
1397 |
| -je podporováno stejné ABI |
| 1394 | +\item low-level binary interface between \emsl{modules} (eg. \texttt{a.out} |
| 1395 | +and \texttt{libc.so.1} or even \texttt{a.out} and \texttt{a.out}) |
| 1396 | +\item \dots{}so that the built module could be used wherever the same ABI is |
| 1397 | +supported |
1398 | 1398 | \end{itemize}
|
1399 | 1399 | \end{slide}
|
1400 | 1400 |
|
1401 | 1401 | \label{API_ABI}
|
1402 | 1402 |
|
1403 | 1403 | \begin{itemize}
|
1404 |
| -\item Pøíkladem API je tøeba API definované normou POSIX.1. |
1405 |
| -\item ABI definuje konvenci volání (to jak program pøedá parametry funkci |
1406 |
| -a jak od ní pøevezme návratovou hodnotu), jaká jsou èísla systémových volání, |
1407 |
| -jak se systémové volání provede èi formát objektového modulu |
1408 |
| -a pøijímaných argumentù, viz pøíklad dole. |
1409 |
| -\item API knihovny pak definuje mimo jiné mno¾inu volání která jsou knihovnou |
1410 |
| -definována, jejich parametry a typy tìchto parametrù. |
1411 |
| -\item následná ukázka je pøíklad na to, kdy vývojáø zmìní velikost argumentù v |
1412 |
| -bajtech (tj. zmìní ABI knihovny), a nahradí novou verzí tu starou. V¹imnìte |
1413 |
| -si, ¾e dynamický linker toto nezjistí; nemá toti¾ jak, øídí se podle jména |
1414 |
| -knihovny v dynamické sekci programu, a to se nezmìnilo. Uvedená zmìna je sice |
1415 |
| -i zmìna v API a problém by se odstranil, kdybychom \texttt{main.c} znovu |
1416 |
| -pøelo¾ili se zmìnìným øádkem deklarace funkce \texttt{add}. To je ale èasto |
1417 |
| -problém (pøe\-klá\-dej\-te celý systém jen kvùli tomu), proto je tak dùle¾ité |
1418 |
| -dodr¾ovat zpìtnou kompatibilitu v ABI u knihoven. |
1419 |
| - |
1420 |
| -Výsledek následujícího pøekladu knihovny, programu a jeho spu¹tìní je jak |
1421 |
| -bychom oèekávali (pou¾it \texttt{cc} ze SunStudio, pro \texttt{gcc} pou¾ijte |
1422 |
| -místo \texttt{-G} volbu \texttt{-shared}; novìj¹í \texttt{gcc} navíc neznají |
1423 |
| -\texttt{-R} a je místo toho nutné pou¾ít \texttt{-Xlinker -R .}: |
| 1404 | +\item In short -- an API is source code based while an ABI is binary based. |
| 1405 | +\item An example of an API is one defined by POSIX.1 standard or the set of |
| 1406 | +system calls for a given system. |
| 1407 | +\item An example of an ABI is System V AMD64 ABI, the one followed on Solaris, |
| 1408 | +Linux, FreeBSD, macOS, and other systems. |
| 1409 | +\item ABI defines calling convention interface to the called machine code, eg. |
| 1410 | +how parameters are passed (pushed on the stack, placed in registers, or a mix |
| 1411 | +of both) or how return value is returned. |
| 1412 | +\item API defines a set of functions, its parameters and their types, and |
| 1413 | +function return values. Part of the API may be also global variables -- |
| 1414 | +\texttt{errno}, for example. |
| 1415 | +\item The following example represents what happens if a library ABI is changed |
| 1416 | +and the new library replaces the old one. Note that the dynamic linker can not |
| 1417 | +detect that as the function symbol did not change. The given change is also an |
| 1418 | +API change and the problem would be fixed if \texttt{main.c} was recompiled |
| 1419 | +with the correct prototype for function \texttt{my\_add}. However, |
| 1420 | +recompiling is often not desirable as one might end up recompiling the whole |
| 1421 | +system. That is why keeping backward compatibility for library ABI is so |
| 1422 | +important. |
| 1423 | + |
| 1424 | +The first result is expected, ie. \texttt{3}: |
1424 | 1425 |
|
1425 | 1426 | \begin{verbatim}
|
1426 | 1427 | $ cat main.c
|
| 1428 | +#include <stdio.h> |
| 1429 | +
|
1427 | 1430 | int my_add(int a, int b);
|
1428 | 1431 |
|
1429 | 1432 | int
|
1430 | 1433 | main(void)
|
1431 | 1434 | {
|
1432 |
| - printf("%d\n", my_add(1, 2)); |
| 1435 | + (void) printf("%d\n", my_add(1, 2)); |
1433 | 1436 | return (0);
|
1434 | 1437 | }
|
1435 | 1438 |
|
|
1440 | 1443 | return (a + b);
|
1441 | 1444 | }
|
1442 | 1445 |
|
1443 |
| -$ cc -G -o libadd.so add.c |
1444 |
| -$ cc -L. -ladd -R. main.c |
| 1446 | +$ gcc -shared -o libadd.so add.c |
| 1447 | +$ gcc -L. -ladd -Xlinker -R . main.c |
1445 | 1448 | $ ./a.out
|
1446 | 1449 | 3
|
1447 | 1450 | \end{verbatim}
|
1448 | 1451 |
|
1449 |
| -Nyní ale pøi¹la dal¹í verze knihovny se stejným jménem, a ve funkci |
1450 |
| -\texttt{my\_add} |
1451 |
| -nastala zmìna v typu argumentù, kde místo 4-bajtového integeru se pou¾ije |
1452 |
| -64-bitový celoèíselný typ. Program ale o nièem neví, nechá se spustit a vrátí |
1453 |
| -chybnou hodnotu: |
| 1452 | +Now imagine a new library came, one with a modified ABI in function |
| 1453 | +\texttt{my\_add}. Note that we replaced the old library with the new one. |
| 1454 | +Now, instead of 4 byte integers, 64-bit longs are used. When you run the |
| 1455 | +program again, you will get an incorrect return value: |
1454 | 1456 |
|
1455 | 1457 | \begin{verbatim}
|
1456 | 1458 | $ cat add2.c
|
|
1460 | 1462 | return (a + b);
|
1461 | 1463 | }
|
1462 | 1464 |
|
1463 |
| -$ cc -G -o libadd.so add2.c |
| 1465 | +$ gcc -shared -o libadd.so add2.c |
1464 | 1466 | $ ./a.out
|
1465 | 1467 | -1077941135
|
1466 | 1468 | \end{verbatim}
|
1467 | 1469 |
|
1468 |
| -\item \label{ABI_MAIN} pøíklad: \example{lib-abi/abi-main.c} (komentáø v |
1469 |
| -souboru napoví jak pou¾ít os\-tat\-ní soubory ve stejném adresáøi) |
1470 |
| - |
1471 |
| - |
1472 |
| -\item zde pak pøichází ke slovu verzování knihoven, tj. je nutné ``nìco'' |
1473 |
| -zmìnit tak, aby po instalaci nové knihovny ne¹lo program spustit bez jeho |
1474 |
| -rekompilace. |
1475 |
| -\item \label{OPENSSL} binární nekompatibilita je napøíklad problém u OpenSSL. |
1476 |
| -Vìtve 0.9.x a 0.9.y nejsou ABI kompatibilní. Konkrétnì verze 0.9.7 a 0.9.8, |
1477 |
| -v roce 2009 stále obì pou¾ívané. Verze rozli¹ené písmeny, tj. napøíklad 0.9.8a a |
1478 |
| -0.9.8g, jsou ABI kompatibilní. Nìkteré systémy stále pou¾ívají pouze 0.9.7 |
1479 |
| -(FreeBSD 6.x, Solaris 10), jiné jen 0.9.8 (Solaris 11 Express), dal¹í integrují |
1480 |
| -obì vìtve (rùzné Linuxové distribuce). Problém je, máte-li napøíklad program pro |
1481 |
| -Solaris~10 pou¾ívající \texttt{libcrypto.so} knihovnu, který chcete pou¾ívat i |
1482 |
| -na Solaris 11 Express (to je jinak díky zpìtné binární kompatibilitì striktnì |
1483 |
| -dodr¾ované mezi "major" verzemi Solarisu mo¾né - napø. program který bì¾el |
1484 |
| -na Solarisu 2.6 z roku 1997 mù¾e bì¾et na Solarisu 10 z roku 2009 bez nutnosti |
1485 |
| -rekompilace - to se týká systému a knihoven s ním dodávaných). |
1486 |
| -Jediné správné re¹ení je zkompilovat pro nový systém, pøípadnì manuálnì |
1487 |
| -zkopírovat potøebné verze knihoven, co¾ ale zdaleka není ideální -- program |
1488 |
| -nebude fungovat s novì nainstalovaným systémem, ale nikdo najednou neví, |
1489 |
| -proè to funguje na stejném systému vedle, a kdy¾ se to zjistí tak je opìt |
1490 |
| -potøeba manuální zásah, a pochybuji o tom, ¾e autor ``øe¹ení'' bude instalovat |
1491 |
| -opravené verze pøi výskytu bezpeènostních chyb. Nekompatibilita 0.9.x verzí je |
1492 |
| -dùvodem, proè je v dynamické sekci knihovny i její celé èíslo (bez písmen, ta |
1493 |
| -jak ji¾ víme nejsou pro ABI kompatibilitu u OpenSSL dùle¾itá), a díky tomu je |
1494 |
| -pak toto èíslo uvedeno i v ka¾dém programu proti knihovnì slinkovanému: |
| 1470 | +\item \label{ABI_MAIN} Example: \example{lib-abi/abi-main.c} (see the block |
| 1471 | +comment in the file on how to use other files located in the same directory). |
| 1472 | +\item To change an ABI safely, you need library versioning -- if the library |
| 1473 | +ABI change is not backward compatible, a bumped up version needs to prevent to |
| 1474 | +run the program without rebuilding it. However, in that case you need to keep |
| 1475 | +the old library in the system. Note that having different versions of the same |
| 1476 | +library might become a problem by itself, for example if more versions of such |
| 1477 | +an library get loaded into the program address space. |
| 1478 | +\item The way how versioning works in ELF (see page \pageref{ELF}) is that the |
| 1479 | +library file name incorporates a version. The \texttt{SONAME} in the dynamic |
| 1480 | +section then lists the full name of the library, including the version. When |
| 1481 | +the loader searches for the libraries, it searches for the filename from the |
| 1482 | +\texttt{SONAME} field. |
| 1483 | +\item Example on what exact libraries and their versions are needed for the |
| 1484 | +Secure shell client on a Linux distribution. You see that, for example, the |
| 1485 | +OpenSSL library version used by the SSH client is 1.0.0. |
| 1486 | + |
1495 | 1487 | \begin{verbatim}
|
1496 |
| -$ elfdump -d /usr/sfw/lib/libcrypto.so.0.9.8 | grep SONAME |
1497 |
| - [7] SONAME 0x1 libcrypto.so.0.9.8 |
1498 |
| -
|
1499 |
| -$ elfdump -d /usr/bin/ssh | grep NEEDED |
1500 |
| - [1] NEEDED 0x3c99 libsocket.so.1 |
1501 |
| - [3] NEEDED 0x3cb1 libnsl.so.1 |
1502 |
| - [5] NEEDED 0x3cc6 libz.so.1 |
1503 |
| - [7] NEEDED 0x3d12 libcrypto.so.0.9.8 |
1504 |
| - [9] NEEDED 0x3cd9 libgss.so.1 |
1505 |
| - [10] NEEDED 0x3cfe libc.so.1 |
| 1488 | +$ readelf -d /usr/bin/ssh |
| 1489 | +
|
| 1490 | +Dynamic section at offset 0xb0280 contains 34 entries: |
| 1491 | + Tag Type Name/Value |
| 1492 | +0x0000000000000001 (NEEDED) Shared library: [libsctp.so.1] |
| 1493 | +0x0000000000000001 (NEEDED) Shared library: [libcrypto.so.1.0.0] |
| 1494 | +0x0000000000000001 (NEEDED) Shared library: [libdl.so.2] |
| 1495 | +0x0000000000000001 (NEEDED) Shared library: [libz.so.1] |
| 1496 | +0x0000000000000001 (NEEDED) Shared library: [libresolv.so.2] |
| 1497 | +0x0000000000000001 (NEEDED) Shared library: [libpthread.so.0] |
| 1498 | +0x0000000000000001 (NEEDED) Shared library: [libgssapi.so.3] |
| 1499 | +0x0000000000000001 (NEEDED) Shared library: [libc.so.6] |
| 1500 | +
|
| 1501 | +$ openssl version |
| 1502 | +OpenSSL 1.0.2n 7 Dec 2017 |
| 1503 | +
|
| 1504 | +$ ls /usr/lib/libcrypto.so.1.0.0 |
| 1505 | +/usr/lib/libcrypto.so.1.0.0 |
1506 | 1506 | \end{verbatim}
|
1507 |
| -\begin{itemize} |
1508 |
| -\item pøíèinou zpìtné nekompatibility OpenSSL verzí je to, ¾e z historických |
1509 |
| -dùvodù jsou nìkteré pou¾ívané struktury v hlavièkových souborech. Tyto struktury |
1510 |
| -je ale nìkdy nutné roz¹íøit, napøíklad pøi vývoji nové funkcionality. Tím |
1511 |
| -nastane situace, ¾e program pøelo¾ený s verzí 0.9.7 by pøedal novìj¹í knihovnì |
1512 |
| -``men¹í'' strukturu, respektive nová knihovna by pøistupovala ve staré struktuøe |
1513 |
| -na polo¾ky, které neexistují -- a tedy by pøistupovala k pamìti, která programu |
1514 |
| -nebyla pøidìlena. To mù¾e zpùsobit pád programu (pøístup na nenamapovanou |
1515 |
| -stránku), mù¾e to fungovat dále (v dané pamìti je to, co se tam typicky oèekává, |
1516 |
| -napøíklad nula), nebo se to zaène chovat ``podivnì'' (v pamìti bylo nìco, co v |
1517 |
| -dané situaci oèekávané nebylo). Problém v OpenSSL je, ¾e nyní ji¾ není technicky |
1518 |
| -jednoduché z tìchto struktur udìlat interní a navenek pracovat jen s |
1519 |
| -transparentními referencemi objektovým pøístupem, co¾ by umo¾nilo dìlat |
1520 |
| -libovolné zmìny ve strukturách, ani¾ by to program ovlivnilo. |
1521 |
| -\item bì¾nì vidìné øe¹ení zpùsobené neznalostí vìci je vytvoøit symbolický link, |
1522 |
| -napøíklad na Solarisu 11 udìlat 0.9.7 symlink na existující knihovnu verze |
1523 |
| -0.9.8. Èastý výsledek je pak pád programu a údiv autora symlinku. Nìkdy to |
1524 |
| -naopak funguje, proto¾e program náhodou nepou¾ívá pøíslu¹né struktury, a to je |
1525 |
| -jasným dùkazem pro aktéra, ¾e øe¹ení musí být správné. Mù¾e se ale stát, ¾e |
1526 |
| -program struktury nepou¾ívá pøi konkrétním provedeném testu, ale zaène dìlat |
1527 |
| -problémy a¾ pøi ¾ivém nasazení. Tady je jediná rada -- pokud si opravdu nejste |
1528 |
| -jisti ¾e víte, co dìláte a nejste si jistí svoji detailní znalostí kódu programu |
1529 |
| -i knihoven, vyhnìte se tomu. Nebo riskujte, ale ji¾ víte jak to mù¾e skonèit. |
1530 |
| -\item zdánlivì jednoduché øe¹ení dodávat více verzí OpenSSL s jedním sys\-té\-mem |
1531 |
| -pøiná¹í zase jiné problémy -- obtí¾nìj¹í vývoj systému, obtí¾nìj¹í správu |
1532 |
| -systému (pøi výskytu bezpeènostní chyby je èasto nutné patchovat v¹echny |
1533 |
| -instalované verze), problémy s nepøímými závislostmi obsahující více verzí dané |
1534 |
| -knihovny apod. |
1535 |
| -\item upgrade verze OpenSSL v existujícím systému je také vìc, které je dobré se |
1536 |
| -vyhnout, respektive toto tì¾ko vyøe¹íte vydáním patche pro existující systémy -- |
1537 |
| -uva¾te ¾e zákazník pou¾ívá své nebo jím koupené programy, které závisí na |
1538 |
| -existující verzi. A tu byste mu najednou upgradovali na verzi vy¹¹í, ABI |
1539 |
| -nekompatibilní. |
1540 |
| -\item typickým pøíkladem, kdy se pou¾ívá transparentní typ jako reference, co¾ |
1541 |
| -umo¾òuje dal¹í roz¹iøování pod ní le¾ící struktury bez rizika vý¹e uvedených |
1542 |
| -problémù, je typ POSIX vláken. Struktura typu \texttt{pthread\_t} (strana |
1543 |
| -\pageref{PTHREAD_T}) je interní zále¾itostí knihovny. Typicky je to integer, ale |
1544 |
| -to by programátora nemìlo vùbec zajímat. Samozøejmì souborový deskriptor èi |
1545 |
| -èíslo procesu jsou podobné pøípady, ale na pøíkladu vláken je to lépe vidìt. |
1546 |
| -\end{itemize} |
| 1507 | + |
| 1508 | +\par The OpenSSL library version is kept 1.0.0 even that the real version is |
| 1509 | +actually 1.0.2n. That is because the micro versions (``z'' in x.y.z) do not |
| 1510 | +change the ABI binary compatibility (change in ``y'' does). So, such a number |
| 1511 | +must not be in the \texttt{SONAME} field otherwise you would need rebuilt |
| 1512 | +binaries that depend on OpenSSL even on a binary compatible micro upgrade. |
1547 | 1513 | \end{itemize}
|
1548 | 1514 |
|
1549 | 1515 | %%%%%
|
|
0 commit comments