Bytekód

Aktuální verze stránky ještě nebyla zkontrolována zkušenými přispěvateli a může se výrazně lišit od verze recenzované 8. srpna 2022; ověření vyžaduje 1 úpravu .

Bytecode ( bytecode ; anglicky  bytecode , také někdy p-code , p-code z přenosného kódu ) je standardní přechodná reprezentace , do které lze automaticky přeložit počítačový program . Ve srovnání se zdrojovým kódem čitelným člověkem je bytecode kompaktní reprezentací programu, který již byl analyzován a analyzován . Explicitně kóduje typy , obory a další konstrukce. Z technického hlediska je bytecode nízkoúrovňový strojově nezávislý kód generovaný překladačem ze zdrojového kódu.

Mnoho moderních programovacích jazyků , zvláště těch interpretovaných , používá bytecode k usnadnění a urychlení práce interpreta . Překlad do bajtového kódu je metoda, která se z hlediska účinnosti nachází mezi přímou interpretací a kompilací do strojového kódu.

Ve formě je bytecode podobný strojovému kódu , ale není určen ke spuštění skutečným procesorem , ale virtuálním strojem . Virtuální stroj je obvykle interpretem odpovídajícího programovacího jazyka (někdy doplněný o kompilátor JIT nebo AOT ). Specifikace bajtového kódu a virtuálních strojů, které jej spouštějí, se mohou jazyk od jazyka značně lišit: bajtový kód se často skládá z instrukcí pro skládaný stroj [1] , ale lze použít i registrační stroje [2] [3] . Většina instrukcí bajtového kódu je však obvykle ekvivalentní jedné nebo více instrukcím v jazyce symbolických instrukcí .

Bytový kód je tak pojmenován, protože každý operační kód je tradičně jeden bajt dlouhý . Každá instrukce je obvykle jednobajtový operační kód (0 až 255), který může být následován různými parametry, jako je číslo registru nebo adresa paměti .

Výkon

Program bajtového kódu je obvykle prováděn interpretem bajtového kódu . Výhodou bajtkódu je větší efektivita a přenositelnost , to znamená, že stejný bajtový kód lze spustit na různých platformách a architekturách , pro které je interpret implementován. Přímo interpretované jazyky poskytují stejnou výhodu, ale protože bajtkód je obvykle méně abstraktní a kompaktnější než zdrojový kód, je interpretace bajtkódu obvykle efektivnější než čistá interpretace zdrojového kódu nebo interpretace AST . Interpret bajtového kódu je navíc často jednodušší než interpret zdrojového kódu a snáze se přenáší (portuje) na jinou hardwarovou platformu.

Vysoce výkonné implementace virtuálních strojů mohou využívat kombinaci tlumočníka a JIT kompilátoru , který převádí často používané fragmenty bajtového kódu do strojového kódu během provádění programu, přičemž aplikuje různé optimalizace. Namísto kompilace JIT lze použít kompilátor AOT , který před spuštěním přeloží bajtový kód do strojového kódu.

Zároveň je možné vytvářet procesory, pro které je daný bytekód přímo strojovým kódem (takové experimentální procesory vznikly např. pro jazyky Java a Forth ).

Historie

Mezi první systémy, které používaly bytecode, byly O-kód pro BCPL (60. léta), Smalltalk (1976) [4] , SIL (System Implementation Language) pro Snobol-4 (1967), p-kód ( p-code , 70. léta, s příspěvky od Niklause Wirtha ) pro přenosné kompilátory programovacího jazyka Pascal [5] [6] [7] .

Varianty p-kódu byly široce používány v různých implementacích jazyka Pascal, jako je UCSD p-System ( UCSD Pascal ). [osm]

Aplikace

Mezi interpretované jazyky, které používají bytecode, patří Perl , PHP (jako Zend Engine ), Ruby (od verze 1.9), Python , Erlang a mnoho dalších.

Rozšířené platformy využívající bajtkód [9] :

Kompilátor Clipper vytvoří spustitelný soubor, který obsahuje bajtový kód přeložený ze zdrojového kódu programu a virtuální stroj, který bajtový kód spustí.

Java programy jsou obvykle kompilovány do souborů třídy, obsahující Java bytecode . Tyto obecné soubory jsou přenášeny do různých cílových počítačů.

První implementace jazyka Visual Basic (před verzí 6) používaly Microsoft p-code na vysoké úrovni [9]

Vysokoúrovňové p-kódy a bajtové kódy byly použity v DBMS , některých implementacích BASICu a Pascalu .

Ve standardu Open Firmware společnosti Sun Microsystems představuje bytecode operátory Forth .

Příklady

Python

Kód:

>>> tisk ( "Ahoj, světe! " ) Ahoj světe !

Bytecode:

>>> import dis #import modulu "dis" - Disassembler bajtového kódu Pythonu do mnemotechnických pomůcek. >>> dis . dis ( 'print("Ahoj, světe!")' ) 1 0 LOAD_NAME 0 ( tisk ) 2 LOAD_CONST 0 ( 'Ahoj, světe!' ) 4 CALL_FUNCTION 1 6 RETURN_VALUE

Java

Kód:

vnější : for ( int i = 2 ; i < 1000 ; i ++ ) { for ( int j = 2 ; j < i ; j ++ ) { if ( i % j == 0 ) pokračovat vnější ; } Systém . ven . println ( i ); }

Bytecode:

0: iconst_2 1: istore_1 2: iload_1 3: sipush 1000 6: if_icmpge 44 9: iconst_2 10: istore_2 11: iload_2 12 : iload_1 13 : if_icmpge 31 16 : iload iload : 3 i2 : 2 17 25: iinc 2 , 1 28: goto 11 31: getstatic #84 ; //Pole java/lang/System.out:Ljava/io/PrintStream; 34: iload_1 35: invokevirtual #85 ; //Metoda java/io/PrintStream.println:(I)V 38: iinc 1 , 1 41: goto 2 44: return

Kritika

Tradičně je bajtkód navržen ve stylu skládaných virtuálních strojů, což zjednodušuje generování z AST , umožňuje jednodušší a kompaktnější kódování bajtového kódu, zjednodušuje interpret a snižuje množství strojového kódu potřebného k provedení jedné instrukce bajtového kódu. Na druhou stranu takové varianty bajtkódu pro daný program obsahují více instrukcí než bajtkódy registrových virtuálních strojů, kvůli čemuž musí interpret provádět více nepřímých skoků, u kterých nefunguje dobře predikce větví [3] . Bytový kód pro registry virtuálních strojů má o něco větší velikost strojových kódů, ale počet instrukcí ve srovnání s bajtkódem zásobníku je asi dvakrát menší a interpret je o desítky procent rychlejší [3] . Také bajtový kód zásobníkových strojů je obtížnější optimalizovat (výrazy se stávají implicitními, související instrukce nejsou seskupeny, výrazy jsou distribuovány do několika základních bloků ) [12] a vyžaduje ověření správnosti použití zásobníku [13] .

Chyby ověření bajtkódu stohovaného stroje vedly k mnoha extrémně nebezpečným zranitelnostem, zejména desítkám ve virtuálním stroji AVM2 používaném v Adobe Flash ke spouštění skriptů ActionScript [14] [15] [16] a několika v raných populárních Java runtime systémech (JVM) [ 17] [18]

Na konci roku 2000 a na začátku roku 2010 autoři kompilátorů V8 (pro JavaScript, často implementovaný prostřednictvím bajtkódu) [19] a Dart [20] zpochybnili potřebu přechodných bajtkódů pro rychlé a efektivní virtuální stroje. Tyto projekty implementovaly přímou kompilaci JIT (kompilaci za běhu) ze zdrojových kódů přímo do strojového kódu. [21]

Poznámky

  1. Terence Parr. Vzory implementace jazyka – Pragmatic Bookshelf, prosinec 2009, ISBN 978-1-934356-45-6 „Část 3: Stavební tlumočníci. Pattern 27 Stack-Based Bytecode Interpreter” Archivováno 26. června 2015 na Wayback Machine
  2. Terence Parr. Vzory implementace jazyka – Pragmatic Bookshelf, prosinec 2009, ISBN 978-1-934356-45-6 „Část 3: Stavební tlumočníci. Pattern 28 Register-Based Bytecode Interpreter" Archivováno 26. června 2015 na Wayback Machine
  3. 1 2 3 Yunhe Shi, David Gregg, Andrew Beatty, M. Anton Ertl. Virtual Machine Showdown: Stack versus Registers  //  VEE '05: Sborník z 1. mezinárodní konference ACM/USENIX o virtuálních prováděcích prostředích. - Chicago, Illinois, USA: ACM, 2005. - S. 153 - 163 . — ISBN 1-59593-047-7 . - doi : 10.1145/1064979.1065001 .
  4. Přináší výkon a škálovatelnost do dynamických jazyků  ​​(nedostupný odkaz) // Mario Wolczko, Oracle 2012 snímek 7
  5. Ruslan Bogatyrev. Chronicle of Pascal Languages ​​​​Archived 30. května 2015 na Wayback Machine , PC World, č. 04/2001
  6. Kompilátory: Principy, techniky a nástroje archivované 4. března 2016 na Wayback Machine  - Williams, ISBN 9785845901897 , strana 517 "12.2 Pascal Compilers"
  7. THE UCSD P-SYSTEM MUSEUM Archivováno 17. února 2015 na Wayback Machine , 2004
  8. 1 2 Understanding .NET: A Tutorial and Analysis Archived 6. března 2016 na Wayback Machine , David Chappell, David Wayne Chappell, 2002, ISBN 9780201741629 strana 92
  9. 1 2 C# versus Java Archivováno 6. dubna 2016 na Wayback Machine / Dr. Dobb's Journal únor 2001
  10. http://www.javaworld.com/article/2077233/core-java/bytecode-basics.html Archivováno 19. května 2015 na Wayback Machine 1996
  11. Alan Jock. Kompilátory, interpreti a bytekód . Computerworld Russia, č. 06, 2001. Získáno 18. května 2015. Archivováno 28. října 2010.
  12. Ando Saabas, Tarmo Uustalu. Typové systémy pro optimalizaci kódu založeného na zásobníku  // Elektronické poznámky v teoretické informatice. - 2007. - Vydání. 190,1 . — s. 103-119. . - doi : 10.1016/j.entcs.2007.02.063 . Archivováno z originálu 26. května 2016. : "Virtuální zásobník nebo virtuální registr VM lze spouštět efektivněji pomocí interpretu. Počítače s virtuálním registrem mohou být atraktivní alternativou ke stackovým architekturám, protože umožňují podstatně snížit počet prováděných instrukcí VM.
  13. Gerwin Klein a Martin Wildmoser, Verified Bytecode Subroutines archivované 10. srpna 2017 na Wayback Machine // Journal of Automated Reasoning 30.3-4 (2003): 363-398. „Ověření bajtkódu je statická kontrola bezpečnosti bajtového kódu. Jeho účelem je zajistit, aby JVM spouštělo pouze bezpečný kód: žádné přetečení nebo podtečení zásobníku operandů, žádné špatně vytvořené instrukce, žádné chyby typu“
  14. Mark Dowd (X-Force Researcher IBM Internet Security Systems), Využití virtuálního stroje ActionScript  (nedostupný odkaz) , IBM 2008 „Pokud by existoval způsob, jak provádět instrukce AS3, které nebyly nikdy ověřeny, bylo by to docela nebezpečné. Neověřené instrukce by mohly manipulovat s nativním runtime zásobníkem… Útok funguje tak, že manipuluje datovou strukturou používanou ověřovatelem AVM2 tak, že správně neověřuje instrukce jazyka ActionScript pro danou metodu."
  15. Haifei Li, Pochopení a využití zranitelností Flash ActionScript Archivováno 26. listopadu 2013. , 2011 “Bytecode -> Verification process … Chyby zabezpečení ActionScriptu jsou způsobeny různými chybami výpočtu toku programu v procesu ověření/generování (tok ověření a tok provedení nejsou stejné)”
  16. Haifei Li (Microsoft), Inside AVM Archivováno 21. listopadu 2014 na Wayback Machine // REcon 2012, Montreal „Většina zranitelností Flash souvisí s ActionScriptem... Chyby při ověřování způsobují vysoce nebezpečné chyby zabezpečení typu JIT. • vysoce nebezpečný znamená dokonalé využití: obcházení ASLR+DEP, se 100% spolehlivostí, žádný heapSpray, žádný JITSpray. • Záměny typu JIT jsou způsobeny chybami při ověřování AVM!“
  17. Poslední fáze výzkumné skupiny deliria, zranitelnosti zabezpečení Java a Java Virtual Machine a jejich techniky využití Archivováno 12. března 2016 na Wayback Machine , BlackHat 2002: „Chyba pramenila ze skutečnosti, že Bytecode Verifier řádně neprovedl analýzu toku bajtového kódu "
  18. Ověření bajtkódu ve virtuálním počítači Archivováno 30. dubna 2013. // International Journal of Advanced Research in Computer Science and Software Engineering Vol.3 Issue 3 March 2013, ISSN 2277-128X: „Ověření bajtového kódu Java bylo rozsáhle studováno z hlediska správnosti a bylo nalezeno a odstraněno několik zranitelností. proces"
  19. Generování dynamického strojového kódu . Google. Získáno 18. 5. 2015. Archivováno z originálu 17. 9. 2013.
  20. Loitsch, Florian Proč ne virtuální počítač s Bytecode? . Google. Získáno 18. 5. 2015. Archivováno z originálu 12. 5. 2013.
  21. Dr. Axel Rauschmayer. Mýtus JavaScriptu: JavaScript potřebuje standardní  bytecode . Získáno 18. 5. 2015. Archivováno z originálu 19. 5. 2015.