Namnmangling
I kompilatorkonstruktion är namnmangling (även kallad namndekoration ) en teknik som används för att lösa olika problem som orsakas av behovet av att lösa unika namn för programmeringsenheter i många moderna programmeringsspråk .
Det ger ett sätt att koda ytterligare information i namnet på en funktion , struktur , klass eller annan datatyp för att skicka mer semantisk information från kompilatorn till länken .
Behovet av namnmangling uppstår när språket tillåter att olika enheter namnges med samma identifierare så länge de upptar ett annat namnutrymme (typiskt definierat av en modul, klass eller explicit namnområdesdirektiv ) eller har olika signaturer (som i funktion ) överbelastning ). Det krävs i dessa användningsfall eftersom varje signatur kan kräva olika, specialiserade anropskonventioner i maskinkoden.
All objektkod som produceras av kompilatorer är vanligtvis länkad med andra delar av objektkod (producerad av samma eller annan kompilator) av en typ av program som kallas länk . Länkaren behöver en hel del information om varje programenhet. Till exempel, för att länka en funktion korrekt behöver den dess namn, antalet argument och deras typer, och så vidare.
De enkla programmeringsspråken på 1970-talet, som C , särskiljde endast subrutiner genom deras namn, och ignorerade annan information inklusive parameter- och returtyper. Senare programmeringsspråk, som C++ , definierade strängare krav för att rutiner ska betraktas som "lika", såsom parametertyper, returtyp och anropskonvention för en funktion. Dessa krav möjliggör metodöverbelastning och upptäckt av vissa buggar (som att använda olika definitioner av en funktion vid kompilering av olika källfiler). Dessa strängare krav behövs för att arbeta med befintliga verktyg och konventioner; därför kodades ytterligare krav i symbolens namn, eftersom det var den enda information som den traditionella länken hade om en symbol.
En annan användning av namnmangling är för att upptäcka ytterligare icke-signaturrelaterade ändringar, såsom funktionsrenhet, eller om det potentiellt kan skapa ett undantag eller utlösa sophämtning. Ett exempel på ett språk som gör detta är D . Dessa är mer av en förenklad felkontroll. Till exempel funktioner int f();
och int g(int) ren;
kunde kompileras till en objektfil, men sedan ändrades deras signaturer till float f(); int g(int);
och används för att kompilera en annan källa som kallar det. Vid länktid kommer länken att upptäcka att det inte finns någon funktion f(int)
och returnera ett fel. På liknande sätt kommer länkaren inte att kunna detektera att returtypen för f
är annorlunda och returnera ett fel. Annars skulle inkompatibla anropskonventioner användas, och troligen ge fel resultat eller krascha programmet. Mangling fångar vanligtvis inte varje detalj i anropsprocessen. Till exempel förhindrar det inte helt fel som ändringar av datamedlemmar i en struktur eller klass. Till exempel, struct S {}; void f(S) {}
skulle kunna kompileras till en objektfil, sedan ändrades definitionen för S
till struct S { int x; };
och används i kompileringen av ett anrop till f(S())
. I sådana fall kommer kompilatorn vanligtvis att använda en annan anropskonvention, men i båda fallen f
att mangla till samma namn, så länkaren kommer inte att upptäcka detta problem, och resultatet blir vanligtvis en krasch eller data- eller minneskorruption vid körning.
Exempel
C
Även om namnmangling i allmänhet inte krävs eller används av språk som inte stöder funktionsöverbelastning , som C och klassiska Pascal , använder de det i vissa fall för att ge ytterligare information om en funktion. Till exempel stöder kompilatorer som är inriktade på Microsoft Windows-plattformar en mängd olika anropskonventioner , som bestämmer hur parametrar skickas till subrutiner och resultat returneras. Eftersom de olika anropskonventionerna är inkompatibla med varandra, manglar kompilatorerna symboler med koder som beskriver vilken konvention som ska användas för att anropa den specifika rutinen.
Manglingsschemat etablerades av Microsoft och har informellt följts av andra kompilatorer inklusive Digital Mars, Borland och GNU GCC vid kompilering av kod för Windows-plattformarna. Schemat gäller även för andra språk, som Pascal , D , Delphi , Fortran och C# . Detta gör att subrutiner skrivna på dessa språk kan anropa, eller anropas av, befintliga Windows-bibliotek med en anropskonvention som skiljer sig från deras standard.
När du sammanställer följande C-exempel:
0
0
0 int _cdecl f ( int x ) { retur ; } int _stdcall g ( int y ) { return ; } int _snabbsamtal h ( int z ) { return ; }
32-bitars kompilatorer sänder ut, respektive:
_f _g@4 @h@4
I stdcall-
och fastcall
-manglingsscheman kodas funktionen som _ namn @ X
respektive @ namn @ X
, där X är antalet byte, i decimal, av argumentet/argumenten i parameterlistan (inklusive de som skickas i register, för snabbsamtal). I fallet med cdecl
är funktionsnamnet bara prefixet av ett understreck.
64-bitarskonventionen på Windows (Microsoft C) har inget ledande understreck. Denna skillnad kan i vissa sällsynta fall leda till olösta externa ämnen vid portering av sådan kod till 64 bitar. Till exempel kan Fortran-kod använda 'alias' för att länka mot en C-metod med namn enligt följande:
SUBRUTIN f () !DEC$ ATTRIBUT C, ALIAS:'_f' :: f AVSLUTA SUBRUTIN
Detta kommer att kompilera och länka bra under 32 bitar, men generera en olöst extern _f
under 64 bitar. En lösning för detta är att inte använda "alias" alls (där metodnamnen vanligtvis måste skrivas med versaler i C och Fortran). En annan är att använda alternativet BIND:
SUBRUTIN f () BIND ( C , NAMN = "f" ) SLUT SUBRUTIN
I C manglar de flesta kompilatorer även statiska funktioner och variabler (och i C++ funktioner och variabler som deklareras statiska eller placeras i det anonyma namnområdet) i översättningsenheter med samma manglingsregler som för deras icke-statiska versioner. Om funktioner med samma namn (och parametrar för C++) också definieras och används i olika översättningsenheter, kommer det också att mangla till samma namn, vilket kan leda till en konflikt. De kommer dock inte att vara likvärdiga om de anropas i sina respektive översättningsenheter. Kompilatorer är vanligtvis fria att avge godtycklig mangling för dessa funktioner, eftersom det är olagligt att komma åt dessa från andra översättningsenheter direkt, så de kommer aldrig att behöva länka mellan olika objektkoder (länkning av dem behövs aldrig). För att förhindra länkkonflikter kommer kompilatorer att använda standardmangling, men kommer att använda så kallade "lokala" symboler. När man länkar många sådana översättningsenheter kan det finnas flera definitioner av en funktion med samma namn, men den resulterande koden kommer bara att anropa en eller annan beroende på vilken översättningsenhet den kom ifrån. Detta görs vanligtvis med hjälp av flyttmekanismen .
C++
C++- kompilatorer är de mest utbredda användarna av namnmangling. De första C++-kompilatorerna implementerades som översättare till C- källkod, som sedan skulle kompileras av en C-kompilator till objektkod; på grund av detta var symbolnamn tvungna att följa C-identifieringsreglerna. Även senare, med uppkomsten av kompilatorer som producerade maskinkod eller sammansättning direkt, stödde systemets länk i allmänhet inte C++-symboler, och mangling krävdes fortfarande.
C ++ -språket definierar inte ett standarddekorationsschema, så varje kompilator använder sin egen. C++ har också komplexa språkfunktioner, såsom klasser , mallar , namnområden och operatörsöverbelastning , som ändrar innebörden av specifika symboler baserat på sammanhang eller användning. Metadata om dessa funktioner kan disambigueras genom att mangla (dekorera) namnet på en symbol . Eftersom namnmanglingssystemen för sådana funktioner inte är standardiserade över kompilatorer, kan få länkare länka objektkod som producerats av olika kompilatorer.
Enkelt exempel
En enda C++-översättningsenhet kan definiera två funktioner som heter f()
:
0
0 int f () { return 1 ; } int f ( int ) { return ; } void g () { int i = f (), j = f ( ); }
Dessa är distinkta funktioner, utan någon relation till varandra förutom namnet. C++-kompilatorn kommer därför att koda typinformationen i symbolnamnet, resultatet blir något som liknar:
0
0 int __f_v () { return 1 ; } int __f_i ( int ) { return ; } void __g_v () { int i = __f_v (), j = __f_i ( ); }
Även om dess namn är unikt, är g()
fortfarande manglad: namnmangling gäller alla C++-symboler (de som inte finns i ett externt "C" {}
-block).
Komplicerat exempel
De manglade symbolerna i det här exemplet, i kommentarerna under respektive identifierarnamn, är de som produceras av GNU GCC 3.x-kompilatorerna, enligt IA-64 (Itanium) ABI:
namnutrymme wikipedia { class article { public : std :: strängformat ( ); // = _ZN9wikipedia7article6formatEv bool print_to ( std :: ostream & ); // = _ZN9wikipedia7article8print_toERSo class wikilink { public : wikilink ( std :: string const & name ); // = _ZN9wikipedia7article8wikilinkC1ERKSs }; }; }
Alla manglade symboler börjar med _Z
(observera att en identifierare som börjar med ett understreck följt av en stor bokstav är en reserverad identifierare i C, så konflikt med användaridentifierare undviks); för kapslade namn (inklusive både namnutrymmen och klasser) följs detta av N
, sedan en serie <length, id>-par (längden är längden på nästa identifierare), och slutligen E
. Till exempel blir wikipedia::artikel::format :
_ZN9wikipedia7artikel6formatE
För funktioner följs detta sedan av typinformationen; eftersom format()
är en void
-funktion är detta helt enkelt v
; därav:
_ZN9wikipedia7artikel6formatEv
För print_to
används standardtypen std::ostream
(som är en typedef för std::basic_ostream<char, std::char_traits<char> > ) som har det speciella aliaset
So
; en referens till denna typ är därför RSo
, med det fullständiga namnet för funktionen är:
_ZN9wikipedia7article8print_toERSo
Hur olika kompilatorer manglar samma funktioner
Det finns inte ett standardiserat schema genom vilket även triviala C++-identifierare manglas, och följaktligen olika kompilatorer (eller till och med olika versioner av samma kompilator, eller samma kompilator på olika plattformar) manglar offentliga symboler i radikalt olika (och därmed totalt inkompatibla) sätt. Tänk på hur olika C++-kompilatorer manglar samma funktioner:
Kompilator |
void h(int)
|
void h(int, char)
|
void h(void)
|
---|---|---|---|
Intel C++ 8.0 för Linux |
_Z1hej
|
_Z1hic
|
_Z1hv
|
HP aC++ A.05.55 IA-64 | |||
IAR EWARM C++ | |||
GCC 3. x och högre | |||
Klang 1. x och högre | |||
GCC 2.9. x |
h__Fi
|
h__Fic
|
h__Fv
|
HP aC++ A.03.45 PA-RISC | |||
Microsoft Visual C++ v6-v10 ( manglingsdetaljer ) |
?h@@YAXH@Z
|
?h@@YAXHD@Z
|
?h@@YAXXZ
|
Digital Mars C++ | |||
Borland C++ v3.1 |
@h$qi
|
@h$qizc
|
@h$qv
|
OpenVMS C++ v6.5 (ARM-läge) |
H__XI
|
H__XIC
|
H__XV
|
OpenVMS C++ v6.5 (ANSI-läge) |
CXX$__7H__FIC26CDH77
|
CXX$__7H__FV2CB06E8
|
|
OpenVMS C++ X7.1 IA-64 |
CXX$_Z1HI2DSQ26A
|
CXX$_Z1HIC2NP3LI4
|
CXX$_Z1HV0BCA19V
|
SunPro CC |
__1cBh6Fi_v_
|
__1cBh6Fic_v_
|
__1cBh6F_v_
|
Tru64 C++ v6.5 (ARM-läge) |
h__Xi
|
h__Xic
|
h__Xv
|
Tru64 C++ v6.5 (ANSI-läge) |
__7h__Fi
|
__7h__Fic
|
__7h__Fv
|
Watcom C++ 10.6 |
W?h$n(i)v
|
W?h$n(ia)v
|
W?h$n()v
|
Anmärkningar:
- Compaq C++-kompilatorn på OpenVMS VAX och Alpha (men inte IA-64) och Tru64 har två namnmanglingsscheman. Det ursprungliga, förstandardiserade schemat är känt som ARM-modellen och är baserat på namnmanglingen som beskrivs i C++ Annotated Reference Manual (ARM). Med tillkomsten av nya funktioner i standard C++, särskilt mallar , blev ARM-schemat mer och mer olämpligt - det kunde inte koda vissa funktionstyper, eller producerade identiskt manglade namn för olika funktioner. Den ersattes därför av den nyare "ANSI"-modellen, som stödde alla ANSI-mallfunktioner, men som inte var bakåtkompatibel.
- På IA-64 finns ett standard Application Binary Interface (ABI) (se externa länkar ), som definierar (bland annat) ett standardnamn-mangling-schema, och som används av alla IA-64-kompilatorer. GNU GCC 3. x har dessutom antagit namnmanglingsschemat som definieras i denna standard för användning på andra icke-Intel-plattformar.
- Visual Studio och Windows SDK inkluderar programmet
undname
som skriver ut funktionsprototypen i C-stil för ett givet manglat namn. - På Microsoft Windows använder Intel-kompilatorn och Clang namnet Visual C++ för kompatibilitet.
Hantering av C-symboler vid länkning från C++
Jobbet med det vanliga C++-idiomet:
#ifdef __cplusplus extern "C" { #endif /* ... */ #ifdef __cplusplus } #endif
är att se till att symbolerna inom är "unmangled" – att kompilatorn sänder ut en binär fil med deras namn odekorerade, som en C-kompilator skulle göra. Eftersom C-språksdefinitioner är unmangled måste C++-kompilatorn undvika att mangla referenser till dessa identifierare.
Till exempel innehåller standardsträngsbiblioteket, <string.h>
, vanligtvis något som liknar:
#ifdef __cplusplus extern "C" { #endif void * memset ( void * , int , size_t ); char * strcat ( char * , const char * ); int strcmp ( const char * , const char * ); char * strcpy ( char * , const char * ); #ifdef __cplusplus } #endif
Alltså kod som:
0
0 if ( strcmp ( argv [ 1 ], "-x" ) == ) strcpy ( a , argv [ 2 ]); annat memset ( a , , storleken på ( a ));
använder korrekt, unmangled strcmp
och memset
. Om det externa "C"
inte hade använts, skulle (SunPro) C++-kompilatorn producera kod motsvarande:
0
0 if ( __1cGstrcmp6Fpkc1_i_ ( argv [ 1 ], "-x" ) == ) __1cGstrcpy6Fpcpkc_0_ ( a , argv [ 2 ]); annars __1cGmemset6FpviI_0_ ( a , , storleken på ( a ));
Eftersom dessa symboler inte finns i C runtime-biblioteket ( t.ex. libc), skulle länkfel uppstå.
Standardiserad namnmangling i C++
Det verkar som om standardiserad namnmangling i C++-språket skulle leda till större interoperabilitet mellan kompilatorimplementeringar. En sådan standardisering i sig skulle dock inte räcka för att garantera interoperabilitet för C++-kompilatorer och det kan till och med skapa ett felaktigt intryck av att interoperabilitet är möjligt och säkert när det inte är det. Namnmangling är bara en av flera applikationsbinära gränssnitt (ABI) detaljer som måste beslutas och observeras av en C++-implementering. Andra ABI-aspekter som undantagshantering , virtuell tabelllayout , struktur och stackframe- utfyllnad gör också att olika C++-implementeringar är inkompatibla. Vidare skulle krav på en viss form av mangling orsaka problem för system där implementeringsbegränsningar (t.ex. längden på symboler) dikterar ett speciellt manglingschema. Ett standardiserat krav på namnmangling skulle också förhindra en implementering där mangling inte alls krävdes - till exempel en länkare som förstod C++-språket.
C ++-standarden försöker därför inte standardisera namnmangling. Tvärtom, den kommenterade C++-referensmanualen (även känd som ARM , ISBN 0-201-51459-1 , avsnitt 7.2.1c) uppmuntrar aktivt användningen av olika manglingscheman för att förhindra länkning när andra aspekter av ABI är inkompatibla.
Ändå, som beskrivs i avsnittet ovan, på vissa plattformar har hela C++ ABI standardiserats, inklusive namnmangling.
Verkliga effekter av C++ namnmangling
Eftersom C++-symboler rutinmässigt exporteras från DLL och delade objektfiler , är namnmanglingsschemat inte bara en kompilatorintern angelägenhet. Olika kompilatorer (eller olika versioner av samma kompilator, i många fall) producerar sådana binärer under olika namndekorationsscheman, vilket betyder att symboler ofta är olösta om kompilatorerna som används för att skapa biblioteket och programmet som använder det använder olika scheman. Till exempel, om ett system med flera C++-kompilatorer installerade (t.ex. GNU GCC och OS-leverantörens kompilator) skulle vilja installera Boost C++ Libraries , skulle det behöva kompileras flera gånger (en gång för GCC och en gång för leverantörens kompilator).
Det är bra av säkerhetsskäl att kompilatorer som producerar inkompatibla objektkoder (koder baserade på olika ABI:er, t.ex. klasser och undantag) använder olika namnmanglingscheman. Detta garanterar att dessa inkompatibiliteter upptäcks vid länkningsfasen, inte när programvaran körs (vilket kan leda till oklara buggar och allvarliga stabilitetsproblem).
Av denna anledning är namndekoration en viktig aspekt av alla C++-relaterade ABI .
Det finns tillfällen, särskilt i stora, komplexa kodbaser, där det kan vara svårt eller opraktiskt att mappa det manglade namnet som sänds ut i ett länkfelmeddelande tillbaka till det specifika motsvarande token/variabelnamnet i källan. Detta problem kan göra det mycket svårt att identifiera relevanta källfiler för bygg- eller testingenjörer även om bara en kompilator och länkare används. Demanglers (inklusive de inom länkningsfelrapporteringsmekanismerna) hjälper ibland men själva manglingsmekanismen kan förkasta kritisk disambiguerande information.
Demontera via c++filt
$ c++filt -n _ZNK3MapI10StringName3RefI8GDScriptE10ComparatorIS0_E16DefaultAllocatorE3hasERKS0_ Map<StringName, Ref<GDScript>, Comparator<StringName>, DefaultAllocator>::has(StringName const&) const
Demontera via inbyggd GCC ABI
0
#include <stdio.h> #include <stdlib.h> #include <cxxabi.h> int main () { const char * mangled_name = "_ZNK3MapI10StringName3RefI8GDScriptE10ComparatorIS0_E16DefaultAllocatorE3hasERKS0_" ; int status = -1 ; char * demangled_name = abi :: __cxa_demangle ( mangled_name , NULL , NULL , & status ); printf ( "Demangled: %s \n " , demangled_name ); gratis ( deangled_name ); återvända ; }
Produktion:
Demonterad: Karta , Komparator , DefaultAllocator>::has(StringName const&) const
Java
I Java innehåller signaturen för en metod eller en klass dess namn och typerna av dess metodargument och returvärde, där så är tillämpligt. Formatet för signaturer är dokumenterat, eftersom språket, kompilatorn och .class-filformatet alla designades tillsammans (och hade objektorientering och universell interoperabilitet i åtanke från början).
Skapa unika namn för inre och anonyma klasser
Omfattningen av anonyma klasser är begränsad till deras överordnade klass, så kompilatorn måste skapa ett "kvalificerat" offentligt namn för den inre klassen , för att undvika konflikter där andra klasser med samma namn (inre eller inte) finns i samma namnutrymme. På samma sätt måste anonyma klasser ha "falska" offentliga namn genererade för dem (eftersom konceptet med anonyma klasser bara finns i kompilatorn, inte körtiden). Så kompilerar följande java-program
public class foo { class bar { public int x ; } public void zark () { Object f = new Object () { public String toString () { return "hello" ; } }; } }
kommer att producera tre .class- filer:
- foo.class , som innehåller den huvudsakliga (yttre) klassen foo
- foo$bar.class , som innehåller den namngivna inre klassen foo.bar
- foo$1.class , som innehåller den anonyma inre klassen (lokal till metoden foo.zark )
Alla dessa klassnamn är giltiga (eftersom $-symboler är tillåtna i JVM-specifikationen) och dessa namn är "säkra" för kompilatorn att generera, eftersom Java-språkdefinitionen avråder från att använda $-symboler i normala Java-klassdefinitioner.
Namnupplösning i Java är ytterligare komplicerad under körning, eftersom fullt kvalificerade klassnamn är unika endast i en specifik klassladdningsinstans . Klassladdare är ordnade hierarkiskt och varje tråd i JVM har en så kallad kontextklassladdare, så i de fall där två olika klassladdare-instanser innehåller klasser med samma namn, försöker systemet först ladda klassen med hjälp av rot- (eller system)-klassladdaren och går sedan ner i hierarkin till kontextklassladdaren.
Java Native Interface
Javas inbyggda metodstöd tillåter Java-språkprogram att anropa program skrivna på ett annat språk (vanligtvis antingen C eller C++). Det finns två problem med namnupplösning här, varken är implementerad på ett särskilt standardiserat sätt:
- JVM till infödd namnöversättning - detta verkar vara mer stabilt, eftersom Oracle gör sitt system offentligt.
- Normal C++ namnmangling - se ovan.
Pytonorm
I Python används mangling för klassattribut som man inte vill att underklasser ska använda och som betecknas som sådana genom att ge dem ett namn med två eller flera inledande understreck och inte mer än ett understreck. Till exempel __sak
att manglas, liksom ___sak
och __sak_
, men __sak__
och __sak___
gör det inte. Pythons körtid begränsar inte åtkomst till sådana attribut, manglingen förhindrar bara namnkollisioner om en härledd klass definierar ett attribut med samma namn.
När man stöter på namnmanglade attribut omvandlar Python dessa namn genom att lägga till ett enda understreck och namnet på den omslutande klassen, till exempel:
>>> klass Test : ... def __mangled_name ( self ): ... pass ... def normal_name ( self ): ... pass >>> t = Test () >>> [ attr for attr in dir ( t ) om "namn" i attr ] ['_Test__mangled_name', 'normal_name']
Pascal
Borlands Turbo Pascal / Delphi-sortiment
För att undvika namnmangling i Pascal, använd:
exporterar myFunc- namnet 'myFunc' , myProc- namnet 'myProc' ;
Gratis Pascal
Free Pascal stöder funktions- och operatörsöverbelastning, därför använder den också namnmangling för att stödja dessa funktioner. Å andra sidan kan Free Pascal anropa symboler definierade i externa moduler skapade med ett annat språk och exportera sina egna symboler för att anropas av ett annat språk. För ytterligare information, se kapitel 6.2 och 7.1 i Free Pascal Programmer's Guide .
Fortran
Namnmangling är också nödvändig i Fortran- kompilatorer, ursprungligen eftersom språket är skiftlägesokänsligt . Ytterligare manglingskrav infördes senare i utvecklingen av språket på grund av tillägget av moduler och andra funktioner i Fortran 90-standarden. Särskilt ärendemangling är ett vanligt problem som måste åtgärdas för att anropa Fortran-bibliotek, såsom LAPACK , från andra språk, såsom C .
På grund av skiftlägesokänslighet måste namnet på en subrutin eller funktion FOO
konverteras till ett standardiserat skiftläge och format av kompilatorn så att det kommer att länkas på samma sätt oavsett skiftläge. Olika kompilatorer har implementerat detta på olika sätt och ingen standardisering har skett. AIX- och HP-UX Fortran-kompilatorerna konverterar alla identifierare till gemener foo
, medan Cray- och Unicos Fortran - kompilatorerna konverterade identifierare till alla versaler FOO
. GNU g77 - kompilatorn konverterar identifierare till gemener plus ett understreck foo_
, förutom att identifierare som redan innehåller ett understreck FOO_BAR
har två understreck foo_bar__
, enligt en konvention som fastställts av f2c . Många andra kompilatorer, inklusive SGI :s IRIX -kompilatorer, GNU Fortran och Intels Fortran-kompilator (förutom på Microsoft Windows), konverterar alla identifierare till gemener plus ett understreck ( foo_
respektive foo_bar_
). På Microsoft Windows har Intel Fortran-kompilatorn som standard versaler utan understreck.
Identifierare i Fortran 90-moduler måste manglas ytterligare, eftersom samma procedurnamn kan förekomma i olika moduler. Eftersom Fortran 2003-standarden kräver att modulprocedurnamn inte kommer i konflikt med andra externa symboler, tenderar kompilatorer att använda modulnamnet och procedurens namn, med en distinkt markör emellan. Till exempel:
modul m innehåller heltalsfunktion fem ( ) fem = 5 ändfunktion femändsmodul m _
I denna modul kommer namnet på funktionen att manglas som __m_MOD_five
(t.ex. GNU Fortran), m_MP_five_
(t.ex. Intels ifort), m.five_
(t.ex. Oracles sun95), etc. Eftersom Fortran inte tillåter överbelastning av namnet på en procedur, men använder generiska gränssnittsblock och generiska typbundna procedurer istället, de manglade namnen behöver inte inkludera ledtrådar om argumenten.
Fortran 2003 BIND-alternativet åsidosätter all namnmangling som görs av kompilatorn, som visas ovan .
Rost
Funktionsnamn är manglade som standard i Rust . Detta kan dock inaktiveras av funktionsattributet #[no_mangle] .
Det här attributet kan användas för att exportera funktioner till C, C++ eller Objective-C. Dessutom, tillsammans med funktionsattributet #[start] eller attributet
#[no_main]
crate, tillåter det användaren att definiera en ingångspunkt i C-stil för programmet.
Rust har använt många versioner av symbolmanglingsscheman som kan väljas vid kompilering med alternativet -Z symbol-mangling-version .
Följande saknar är definierade:
-
äldre
mangling i C++-stil baserad på Itanium IA-64 C++ ABI. Symboler börjar med_ZN
och filnamnshashar används för disambiguation. Använd sedan Rust 1.9. -
v0
En förbättrad version av det äldre systemet, med ändringar för Rust. Symboler börjar med_R
. Polymorfism kan kodas. Funktioner har inte returtyper kodade (Rust har ingen överbelastning). Unicode-namn använder modifierad punycode . Komprimering (bakåtreferens) använder bytebaserad adressering. Använd sedan Rust 1.37.
Exempel finns i testerna med Rustsymbolnamn .
Mål-C
Det finns i huvudsak två former av metod i Objective-C , klassen ("statisk") metoden och instansmetoden . En metoddeklaration i Objective-C har följande form:
00 + ( returtyp ) namn : parameternamn 1 : parameter 1 ... – ( returtyp ) namn : parameternamn 1 : parameter 1 ... 00
Klassmetoder betecknas med +, instansmetoder använder -. En typisk klassmetoddeklaration kan då se ut så här:
+ ( id ) initWithX: ( int ) nummer ochY: ( int ) nummer ; + ( id ) ny ;
Med instansmetoder som ser ut så här:
- ( id ) värde ; - ( id ) setValue: ( id ) nytt_värde ;
Var och en av dessa metoddeklarationer har en specifik intern representation. När den kompileras namnges varje metod enligt följande schema för klassmetoder:
0 _c_ Klass _ namn _ namn 1 _ ...
och detta till exempel metoder:
0 _i_ Klass _ namn _ namn 1 _ ...
Kolonen i Objective-C-syntaxen översätts till understreck. Så, klassmetoden Objective-C + ( id ) initWithX: ( int ) nummer och Y: ( int ) nummer ;
, om tillhörande till klassen Point
skulle översättas till _c_Point_initWithX_andY_
och instansmetoden (som tillhör samma klass) - ( id ) värde ;
skulle översättas till _i_Point_value
.
Var och en av metoderna i en klass är märkta på detta sätt. Men att slå upp en metod som en klass kan svara på skulle vara tråkigt om alla metoder representeras på detta sätt. Var och en av metoderna tilldelas en unik symbol (som ett heltal). En sådan symbol är känd som en väljare . I Objective-C kan man hantera väljare direkt — de har en specifik typ i Objective-C — SEL
.
Under kompileringen byggs en tabell som mappar textrepresentationen, såsom _i_Point_value
, till väljare (som ges en typ SEL
). Att hantera väljare är mer effektivt än att manipulera textrepresentationen av en metod. Observera att en väljare bara matchar en metods namn, inte klassen den tillhör — olika klasser kan ha olika implementeringar av en metod med samma namn. På grund av detta får implementeringar av en metod också en specifik identifierare, dessa är kända som implementeringspekare, och de ges även en typ, IMP
.
Meddelandesändningar kodas av kompilatorn som anrop till funktionen id objc_msgSend ( id- mottagare , SEL -väljare , ...)
eller en av dess kusiner, där mottagaren
är mottagaren av meddelandet, och SEL
bestämmer metoden att anropa. Varje klass har sin egen tabell som mappar väljare till deras implementeringar - implementeringspekaren anger var i minnet den faktiska implementeringen av metoden finns. Det finns separata tabeller för klass- och instansmetoder. Förutom att de lagras i SEL
till IMP-
uppslagstabellerna är funktionerna i huvudsak anonyma.
SEL -
värdet för en väljare varierar inte mellan klasserna. Detta möjliggör polymorfism .
Objective-C runtime upprätthåller information om argument och returtyper av metoder. Denna information är dock inte en del av namnet på metoden och kan variera från klass till klass.
Eftersom Objective-C inte stöder namnutrymmen finns det inget behov av att mangla klassnamn (som visas som symboler i genererade binärer).
Snabb
Swift behåller metadata om funktioner (och mer) i de manglade symbolerna som refererar till dem. Denna metadata inkluderar funktionens namn, attribut, modulnamn, parametertyper, returtyp och mer. Till exempel:
Det manglade namnet för en metod func calculate(x: int) -> int
för en MyClass
-klass i modultest är
_TFC4test7MyClass9calculatefS0_FT1xSi_Si ,
för 2014 Swift. Komponenterna och deras betydelser är följande:
-
_T
: Prefixet för alla Swift-symboler. Allt kommer att börja med detta. -
F
: Icke-curried funktion. -
C
: Funktion av en klass, dvs en metod -
4test
: Modulnamn, med prefixet dess längd. -
7MyClass
: Namn på klass funktionen tillhör, med prefixet dess längd. -
9calculate
: Funktionsnamn med dess längd före. -
f
: Funktionsattributet. I det här fallet "f", vilket betyder en normal funktion. -
S0
: Betecknar typen av den första parametern (nämligen klassinstansen) som den första i typstacken (här ärMyClass
inte kapslad och har därmed index 0). -
_FT
: Detta startar typlistan för funktionens parametertuppel. -
1x
: Externt namn på funktionens första parameter. -
Si
: Indikerar inbyggd Swift-typ Swift.Int för den första parametern. -
_Si
: Returtypen: igen Swift.Int.
Mangling för versioner sedan Swift 4.0 är dokumenterad officiellt. Den behåller viss likhet med Itanium.
Se även
- Application Programming Interface (API)
- Application Binary Interface (ABI)
- Calling Convention
- Jämförelse av programvara för applikationsvirtualisering (dvs. virtuella datorer)
- Utländska funktionsgränssnitt (FFI)
- Java Native Interface (JNI)
- Språkbindande
- Stroppning
- SLURK
externa länkar
- Linux Itanium ABI för C++ , inklusive namnmanglingschema.
- Macintosh C/C++ ABI standardspecifikation
- c++filt — filter för att avlägsna kodade C++-symboler för GNU/Intel-kompilatorer
- undname — msvc-verktyg för att avlägsna namn.
- demangler.com — Ett onlineverktyg för att demontera GCC- och MSVC C++-symboler
- Objective-C Runtime System — från Apples The Objective-C-programmeringsspråk 1.0
- Anropskonventioner för olika C++-kompilatorer av Agner Fog innehåller detaljerad beskrivning av namnmanglingsscheman för olika x86- och x64 C++-kompilatorer (sid. 24–42 i 2011-06-08 version)
- C++ Name Mangling/Demangling Ganska detaljerad förklaring av Visual C++ kompilatornamn mangling
- PHP UnDecorateSymbolName ett php-skript som demonterar Microsoft Visual C:s funktionsnamn.
- Blanda C och C++-kod
- Levine, John R. (2000) [oktober 1999]. "Kapitel 5: Symbolhantering" . Länkare och lastare . Morgan Kaufmann-serien i mjukvaruteknik och programmering (1 upplaga). San Francisco, USA: Morgan Kaufmann . ISBN 1-55860-496-0 . OCLC 42413382 . Arkiverad från originalet 2012-12-05 . Hämtad 2020-01-12 . Kod: [1] [2] Errata: [3]
- Namnmangling avmystifierad av Fivos Kefallonitis