Monteringsinsats

I programmering hänvisar inline assembler till kompilatorns förmåga att bädda in lågnivåkod skriven i assembler i ett program skrivet på ett högnivåspråk, som C eller Ada . Användningen av assemblerinsatser kan eftersträva följande mål:

Ett exempel på optimering och användning av speciella processorinstruktioner

Det här exemplet på assemblerinsättning i programmeringsspråket D , som implementerar beräkningen av tangenten för x, använder x86 FPU- instruktioner . Denna kod körs snabbare än koden som kan genereras av kompilatorn. Dessutom används instruktionen här fldpi, som laddar den närmaste sifferuppskattningen för x86-arkitekturen.

// Beräkna tangenten för x real tan ( real x ) { asm { fld x [ EBP ] ; // ladda x fxam ; // testa för udda värden fstsw AX ; sahf ; jc trigerr ; // x är NAN, infinity eller tom // 387 kan hantera denormala SC18 : fptan ; fstp ST ( 0 ) ; // dump X, som alltid är 1 fstsw AX ; sahf ; jnp Lret ; // C2 = 1 (x är utanför intervallet) // Gör argumentreduktion för att få x till intervallet fldpi ; fxch ; SC17 : fpreml ; fstsw AX ; sahf ; jp SC17 ; fstp ST ( 1 ) ; // ta bort pi från stack jmp SC18 ; } trigerr : returnera verklig . nan ; Lret : ; }

Exempel på systemanrop

Att komma åt operativsystemet direkt är i allmänhet inte möjligt med skyddat minne. OS körs på en mer privilegierad nivå (kärnläge) än användaren (användarläge). För att göra förfrågningar till operativsystemet används mjukvaruavbrott. Sällan högnivåspråk stöder denna funktion, så systemanropsgränssnitt skrivs med hjälp av inline assembler [1] .

Följande C-exempel innehåller ett systemanropsgränssnitt skrivet med AT&T :s GNU Assembler -syntax . Låt oss först titta på assembler-insättningsformatet med ett enkelt exempel:

asm ( "movl %ecx, %eax" ); /* flyttar innehållet i ecx till eax */

Identifierarna asmoch __asm__är likvärdiga. Ett annat enkelt exempel på infogning:

__asm__ ( "movb %bh, (%eax)" ); /* flyttar byten från bh till minnet som pekas av eax */

Ett exempel på implementering av systemanropsgränssnittet:

extern int errno ; int funknamn ( int arg1 , int * arg2 , int arg3 ) { int res ; __asm__ flyktig ( "int $0x80" /* gör begäran till OS */ : "=a" ( res ), /* returnerar resultat i eax ("a") */ "+b" ( arg1 ), /* skicka arg1 i ebx ("b") */ "+c" ( arg2 ), /* skicka arg2 i ecx ("c") */ "+d" ( arg3 ) /* skicka arg3 i edx ("d") */ : "a" ( 128 ) /* skicka systemets anropsnummer i eax ("a") */ : "minne" , "cc" ); /* meddela kompilatorn att minnes- och villkorskoderna har modifierats */ /* Operativsystemet returnerar ett negativt värde vid fel; * wrappers returnerar -1 vid fel och ställer in den globala variabeln errno */ if ( -125 <= res && res < 0 ) { errno = -res ; _ res = -1 ; } returnera res ; }

Kritik

Sedan början av 2000-talet har användningen av monteringsskär alltmer fördömts av en mängd olika skäl [2] [3] :

  • Moderna optimeringskompilatorer kan generera bättre assemblerkod än vad en genomsnittlig programmerare kan skriva. I sig själva kan assembler-inlägg störa optimeringen av andra delar av koden. Vissa knep som gjorde det möjligt att optimera exekveringen av kod på processorer från 1980-90-talet på senare processorer kan leda till en betydande nedgång i exekveringen på grund av en annan organisation av beräkningar. Som med all optimering måste assembler-insatser testas för att testa hypotesen om deras effektivitet. På grund av den ökade prestandan hos datorsystem kan många optimeringar vara irrelevanta, och kodläsbarhet, enkel underhåll och felförebyggande kommer i förgrunden.
  • Monteringskod är mer tidskrävande att skriva. Det är lätt att göra fel i monterinsatsen, vilket är svårt att märka. Till exempel, assemblerspråk stöder inte typkontroll . Redan genererad monteringskod är svårare att underhålla .
  • Monteringskoden är inte bärbar. Monteringsinsatser är motiverade för att komma åt plattformsspecifika mekanismer. När du använder assembler-inlägg i plattformsoberoende program är det nödvändigt att duplicera assembler-inlägg för olika plattformar, och även, om möjligt, behålla en alternativ implementering på ett språk på hög nivå - men denna praxis skapar problem vid underhåll av programmet på grund av behöver göra ändringar parallellt med flera kodavsnitt skrivna på olika språk, språk och för olika plattformar.

Anteckningar

  1. 1 2 "Linuxprogrammering" Kapitel 5. Hur systemanrop fungerar . Opennet. Datum för åtkomst: 29 september 2013. Arkiverad från originalet den 2 oktober 2013.
  2. Analys av användningen av assembler-inlägg i koden för öppna projekt . öppet nät . Hämtad 3 maj 2022. Arkiverad från originalet 3 maj 2022.
  3. Anledningar till att du INTE bör använda inline asm . Hämtad 3 maj 2022. Arkiverad från originalet 28 april 2022.

Länkar