Inserție de asamblare

În programare , asamblatorul inline se referă la capacitatea compilatorului de a încorpora cod de nivel scăzut scris în asamblator într-un program scris într -un limbaj de nivel înalt , cum ar fi C sau Ada . Utilizarea inserțiilor de asamblare poate urmări următoarele obiective:

Un exemplu de optimizare și utilizare a instrucțiunilor speciale ale procesorului

Acest exemplu de inserare a asamblatorului în limbajul de programare D , care implementează calculul tangentei lui x, utilizează instrucțiuni x86 FPU . Acest cod rulează mai repede decât codul care ar putea fi generat de compilator. De asemenea, se folosește instrucțiunea de aici , care încarcă cea mai apropiată aproximare a numărului pentru arhitectura x86. fldpi

// Calculați tangenta lui x real tan ( real x ) { asm { fld x [ EBP ] ; // încărcare x fxam ; // testează valorile ciudate fstsw AX ; sahf ; jc trigerr ; // x este NAN, infinit sau gol // 387 pot gestiona denormalele SC18 : fptan ; fstp ST ( 0 ) ; // dump X, care este întotdeauna 1 fstsw AX ; sahf ; jnp Lret ; // C2 = 1 (x este în afara intervalului) // Efectuați reducerea argumentelor pentru a aduce x în intervalul fldpi ; fxch ; SC17 : fprem1 ; fstsw AX ; sahf ; jp SC17 ; fstp ST ( 1 ) ; // elimina pi din stiva jmp SC18 ; } trigerr : return real . nan ; Lret : ; }

Exemplu de apel de sistem

Accesarea directă a sistemului de operare nu este, în general, posibilă cu memoria protejată. Sistemul de operare rulează la un nivel mai privilegiat (mod kernel) decât utilizatorul (modul utilizator). Pentru a face cereri către sistemul de operare, sunt folosite întreruperi software. Rareori limbile de nivel înalt acceptă această caracteristică, astfel încât interfețele de apel de sistem sunt scrise folosind un asamblator inline [1] .

Următorul exemplu C conține o interfață de apel de sistem scrisă folosind sintaxa AT&T GNU Assembler . Mai întâi, să ne uităm la formatul de inserare a asamblatorului folosind un exemplu simplu:

asm ( "movl %ecx, %eax" ); /* mută conținutul ecx în eax */

Identificatorii asmși __asm__sunt echivalente. Un alt exemplu simplu de inserare:

__asm__ ( "movb %bh, (%eax)" ); /* mută octetul din bh în memoria indicată de eax */

Un exemplu de implementare a interfeței de apel de sistem:

extern int errno ; int funcname ( int arg1 , int * arg2 , int arg3 ) { int res ; __asm__ volatil ( "int $0x80" /* faceți cererea către sistemul de operare */ : "=a" ( res ), /* returnează rezultatul în eax ("a") */ "+b" ( arg1 ), /* trece arg1 în ebx ("b") */ "+c" ( arg2 ), /* trece arg2 în ecx ("c") */ "+d" ( arg3 ) /* trece arg3 în edx ("d") */ : "a" ( 128 ) /* trece numărul de apel de sistem în eax ("a") */ : „memorie” , „cc” ); /* anunță compilatorului că memoria și codurile de condiție au fost modificate */ /* Sistemul de operare va returna o valoare negativă în caz de eroare; * wrapper-urile returnează -1 la eroare și setează variabila globală errno */ if ( -125 <= res && res < 0 ) { errno = -res ; _ res = -1 ; } return res ; }

Critica

De la începutul secolului al XXI-lea, utilizarea inserțiilor de asamblare a fost din ce în ce mai condamnată din mai multe motive [2] [3] :

  • Compilatoarele moderne de optimizare sunt capabile să genereze un cod de asamblare mai bun decât poate scrie un programator mediu. Prin ele însele, inserțiile de asamblare pot interfera cu optimizarea altor părți ale codului. Unele trucuri care au făcut posibilă optimizarea execuției codului pe procesoarele anilor 1980-90 pe procesoarele ulterioare pot duce la o încetinire semnificativă a execuției din cauza unei organizări diferite a calculelor. Ca și în cazul oricărei optimizări , inserțiile de asamblare trebuie testate pentru a testa ipoteza despre eficacitatea lor. Datorită creșterii performanței sistemelor de calcul, multe optimizări pot fi irelevante, iar lizibilitatea codului, ușurința întreținerii și prevenirea erorilor ies în prim-plan.
  • Codul de asamblare necesită mai mult timp pentru scriere. Este ușor să faceți o greșeală în inserția de asamblare, ceea ce este greu de observat. De exemplu, limbajul de asamblare nu acceptă verificarea tipului . Codul de asamblare deja generat este mai dificil de întreținut .
  • Codul de asamblare nu este portabil. Inserțiile de asamblare sunt justificate pentru accesarea mecanismelor specifice platformei. Când utilizați inserții de asamblare în programe multi-platformă , este necesar să se dubleze inserțiile de asamblare pentru diferite platforme și, de asemenea, dacă este posibil, să se păstreze o implementare alternativă într-un limbaj de nivel înalt - dar această practică creează probleme la întreținerea programului din cauza trebuie să faceți modificări în paralel cu mai multe secțiuni de cod scrise în diferite limbi.limbi și pentru diferite platforme.

Note

  1. 1 2 „Programare Linux” Capitolul 5. Cum funcționează apelurile de sistem . Opennet. Data accesului: 29 septembrie 2013. Arhivat din original pe 2 octombrie 2013.
  2. Analiza utilizării inserțiilor de asamblare în codul proiectelor deschise . opennet . Preluat la 3 mai 2022. Arhivat din original la 3 mai 2022.
  3. Motive pentru care NU ar trebui să utilizați inline asm . Preluat la 3 mai 2022. Arhivat din original la 28 aprilie 2022.

Link -uri