|
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