İsim değiştirme - Name mangling

İçinde derleyici inşaat, isim değiştirme (olarak da adlandırılır isim dekorasyonu) birçok modernde programlama varlıkları için benzersiz isimleri çözme ihtiyacından kaynaklanan çeşitli sorunları çözmek için kullanılan bir tekniktir. Programlama dilleri.

Adına ek bilgileri kodlamanın bir yolunu sağlar. işlevi, yapı, sınıf veya başkası veri tipi daha fazla anlamsal bilgi iletmek için derleyici için bağlayıcı.

Ad değiştirme ihtiyacı, dilin farklı varlıkların aynı isimle adlandırılmasına izin verdiği durumlarda ortaya çıkar. tanımlayıcı farklı bir yerde bulundukları sürece ad alanı (tipik olarak bir modül, sınıf veya açık ad alanı direktif) veya farklı imzalara sahip (örn. fonksiyon aşırı yükleme ). Bu kullanım durumlarında gereklidir, çünkü her imza farklı, özel çağrı geleneği makine kodunda.

Hiç nesne kodu derleyiciler tarafından üretilen, genellikle diğer nesne kodu parçalarıyla (aynı veya başka bir derleyici tarafından üretilen), a adı verilen bir program türü ile bağlantılıdır. bağlayıcı. Bağlayıcının her program varlığı hakkında çok fazla bilgiye ihtiyacı vardır. Örneğin, bir işlevi doğru şekilde bağlamak için ismine, argüman sayısına ve türlerine vb. İhtiyacı vardır.

1970'lerin basit programlama dilleri C parametre türleri veya dönüş türleri gibi diğer bilgileri göz ardı ederek kod parçalarını yalnızca adlarına göre ayırt etti. C ++, parametre türleri, dönüş türü ve bir işlevin çağırma kuralı gibi "eşit" kabul edilecek kod parçaları için daha katı gereksinimler tanımladı. Bu gereksinimler, işlev aşırı yüklemesinin kullanılmasının yanı sıra çeşitli hataların tespit edilmesini de sağlar (farklı kaynak dosyaları derlemek için bir işlevin farklı tanımlarını kullanmak gibi) Mevcut araçlarla ve kurallarla çalışmak için gerekli olan bu daha katı gereksinimler, bu nedenle adda kodlanmıştır. Bu, geleneksel bağlayıcının bir sembol hakkında sahip olduğu tek bilgiydi.

Ad karıştırmanın başka bir kullanımı, işlev saflığı veya potansiyel olarak bir istisna atıp atmayacağı veya çöp toplamayı tetikleyip tetikleyemeyeceği gibi imza dışı ek değişiklikleri algılamaktır. Bunu yapan bir dil örneği D.[1][2] Bunlar daha çok basitleştirilmiş bir hata kontrolüdür. Örneğin, işlevler int f (); ve int g (int) saf; tek bir nesne dosyasında derlenebilir, ancak daha sonra imzaları şu şekilde değişir: float f (); int g (int); ve onu çağıran diğer kaynağı derlemek için kullanılır. Bağlantı anında bağlayıcı, işlev olmadığını algılar f (int) ve bir hata döndür. Benzer şekilde, bağlayıcı, dönüş türünün olduğunu algılayamayacaktır. f farklıdır ve bir hata döndürür. Aksi takdirde, uyumsuz arama kuralları kullanılacak ve büyük olasılıkla yanlış sonuç üretecek veya programı çökertecektir. Mangling, genellikle arama sürecinin her ayrıntısını yakalamaz. Örneğin, bir yapının veya sınıfın veri üyelerinin değişmesi gibi hataları tam olarak engellemez. Örneğin, struct S {}; geçersiz f (S) {} bir nesne dosyasında derlenebilir, ardından S olarak değişti struct S {int x; }; ve bir çağrının derlenmesinde kullanılır f (S ()). Bu gibi durumlarda, derleyici genellikle farklı bir çağrı kuralı kullanır, ancak her iki durumda da f aynı adı alacak, böylece bağlayıcı bu sorunu algılamayacak ve sonuç genellikle çalışma zamanında bir çökme veya veri veya bellek bozulması olacaktır.

Örnekler

C

Ad değiştirme genellikle gerekli olmasa da veya desteklemeyen diller tarafından kullanılmasa da fonksiyon aşırı yükleme, sevmek C ve klasik Pascal, bazı durumlarda bir işlev hakkında ek bilgi sağlamak için kullanırlar.Örneğin, Microsoft Windows platformlarını hedefleyen derleyiciler çeşitli çağrı kuralları, parametrelerin alt yordamlara gönderilme ve sonuçların döndürülme biçimini belirler. Farklı arama kuralları birbiriyle uyumlu olmadığından, derleyiciler, belirli rutini çağırmak için hangi kuralın kullanılması gerektiğini detaylandıran kodlarla sembolleri karıştırır.

Karıştırma şeması Microsoft tarafından oluşturulmuş ve Windows platformları için kod derlerken Digital Mars, Borland ve GNU GCC gibi diğer derleyiciler tarafından gayri resmi olarak takip edilmiştir. Plan, aşağıdaki gibi diğer diller için bile geçerlidir: Pascal, D, Delphi, Fortran, ve C #. Bu, bu dillerde yazılan alt yordamların varsayılanlardan farklı bir çağrı kuralı kullanarak mevcut Windows kitaplıklarını çağırmasına veya bu kitaplıklar tarafından çağrılmasına olanak tanır.

Aşağıdaki C örneklerini derlerken:

int _cdecl    f (int x) { dönüş 0; }int _stdcall  g (int y) { dönüş 0; }int _fastcall h (int z) { dönüş 0; }

32 bit derleyiciler sırasıyla yayınlar:

_f_g @ 4 @ h @ 4

İçinde stdcall ve hızlı arama düzenleri karıştırırken, işlev şu şekilde kodlanır _isim@X ve @isim@X sırasıyla nerede X parametre listesindeki bağımsız değişkenlerin ondalık bayt sayısıdır (hızlı arama için kayıtlarda iletilenler dahil). Bu durumuda cdeclişlev adı yalnızca bir alt çizgi ile başlar.

Windows (Microsoft C) üzerindeki 64-bit kuralının başında alt çizgi yoktur. Bu fark, bazı nadir durumlarda, bu tür bir kodu 64 bite taşırken çözümlenmemiş harici cihazlara yol açabilir. Örneğin, Fortran kodu bir C yöntemine aşağıdaki gibi adla bağlanmak için 'takma ad' kullanabilir:

ALTROUTİN f()! DEC $ ATTRIBUTES C, ALIAS: '_ f' :: fSON ALTROUTİN

Bu, 32 bitin altında derleme ve bağlantı sağlar, ancak çözülmemiş bir harici _f 64 bitin altında. Bunun için bir çözüm, 'takma ad' kullanmamaktır (burada yöntem adlarının genellikle C ve Fortran'da büyük harfle yazılması gerekir). Bir diğeri BIND seçeneğini kullanmaktır:

ALTROUTİN f() BIND(C,İSİM="f")SON ALTROUTİN

C'de, çoğu derleyici aynı zamanda statik olmayan sürümleriyle aynı karıştırma kurallarını kullanarak çeviri birimlerinde statik işlevleri ve değişkenleri (ve C ++ işlevlerinde ve değişkenleri statik olarak tanımlanmış veya anonim ad alanına yerleştirilmiş) karıştırır. Aynı ada (ve C ++ için parametreler) sahip işlevler de tanımlanır ve farklı çeviri birimlerinde kullanılırsa, aynı ada da karışarak potansiyel olarak bir çatışmaya yol açar. Ancak, ilgili çeviri birimlerinde çağrılırlarsa eşdeğer olmayacaklardır. Derleyiciler genellikle bu işlevler için keyfi karıştırmada özgürdür, çünkü bunlara doğrudan diğer çeviri birimlerinden erişmek yasa dışıdır, bu nedenle farklı nesne kodları arasında hiçbir zaman bağlantıya ihtiyaç duymazlar (bunların bağlanmasına asla gerek yoktur). Bağlanma çakışmalarını önlemek için, derleyiciler standart karıştırmayı kullanırlar, ancak sözde 'yerel' semboller kullanırlar. Bu tür birçok çeviri birimini birbirine bağlarken, aynı ada sahip bir işlevin birden çok tanımı olabilir, ancak ortaya çıkan kod, hangi çeviri biriminden geldiğine bağlı olarak yalnızca birini veya diğerini çağıracaktır. Bu genellikle yer değiştirme mekanizma.

C ++

C ++ derleyiciler, ad bozmanın en yaygın kullanıcılarıdır. İlk C ++ derleyicileri, çevirmenler olarak uygulandı. C daha sonra bir C derleyicisi tarafından nesne koduna derlenecek olan kaynak kodu; bu nedenle, sembol adlarının C tanımlayıcı kurallarına uyması gerekiyordu. Daha sonra, doğrudan makine kodu veya derleme üreten derleyicilerin ortaya çıkmasıyla, sistemin bağlayıcı genellikle C ++ sembollerini desteklemiyordu ve karıştırma hala gerekliydi.

C ++ dil standart bir dekorasyon şeması tanımlamaz, bu nedenle her derleyici kendi şemasını kullanır. C ++ ayrıca karmaşık dil özelliklerine de sahiptir. sınıflar, şablonlar, ad alanları, ve operatör aşırı yükleme, bağlama veya kullanıma göre belirli sembollerin anlamını değiştiren. Bu özellikler hakkındaki meta veriler, bir adın karıştırılmasıyla (süslenmesiyle) netleştirilebilir. sembol. Bu tür özellikler için ad değiştirme sistemleri derleyiciler arasında standartlaştırılmadığından, birkaç bağlayıcı, farklı derleyiciler tarafından üretilen nesne kodunu bağlayabilir.

Basit örnek

Tek bir C ++ çeviri birimi, f ():

int  f () { dönüş 1; }int  f (int)  { dönüş 0; }geçersiz g () { int ben = f(), j = f(0); }

Bunlar, isim dışında birbirleriyle hiçbir ilişkisi olmayan farklı işlevlerdir. C ++ derleyicisi bu nedenle sembol adındaki tür bilgisini kodlayacaktır ve sonuç şuna benzer bir sonuç olacaktır:

int  __f_v () { dönüş 1; }int  __f_i (int)  { dönüş 0; } geçersiz __g_v () { int ben = __f_v(), j = __f_i(0); }

Adı benzersiz olsa da, g () hala parçalanmış: ad değiştirme geçerli herşey C ++ sembolleri (bir dış "C"{} blok).

Karmaşık örnek

Bu örnekte, ilgili tanımlayıcı adının altındaki yorumlarda karıştırılmış semboller, IA-64 (Itanium) ABI'ye göre GNU GCC 3.x derleyicileri tarafından üretilenlerdir:

ad alanı wikipedia {   sınıf makale    {   halka açık:      std::dizi biçim ();  // = _ZN9wikipedia7article6formatEv      bool print_to (std::Ostream&);  // = _ZN9wikipedia7article8print_toERSo      sınıf Wikilink       {      halka açık:         Wikilink (std::dizi sabit& isim);  // = _ZN9wikipedia7article8wikilinkC1ERKSs      };   };}

Tüm karıştırılmış semboller ile başlar _Z (alt çizgiyle başlayan ve ardından büyük harfle başlayan bir tanımlayıcının bir ayrılmış tanımlayıcı C'de, kullanıcı tanımlayıcıları ile çakışma önlenir); iç içe geçmiş adlar için (hem ad alanları hem de sınıflar dahil), bunu takip eder N, sonra bir dizi çifti (uzunluk, bir sonraki tanımlayıcının uzunluğudur) ve son olarak E. Örneğin, wikipedia :: article :: format şu hale gelir:

_ZN9wikipedia7article6formatE

Fonksiyonlar için, bunu daha sonra tip bilgisi takip eder; gibi biçim() bir geçersiz işlev, bu basitçe v; dolayısıyla:

_ZN9wikipedia7article6formatEv

İçin print_tostandart tip std :: ostream (hangisi bir typedef için std :: basic_ostream >) özel takma adı olan kullanılır Yani; bu nedenle bu türe bir referans RSo, işlevin tam adı:

_ZN9wikipedia7article8print_toERSo

Farklı derleyiciler aynı işlevleri nasıl kullanır?

Önemsiz C ++ tanımlayıcılarının bile karıştırıldığı ve sonuç olarak farklı derleyicilerin (hatta aynı derleyicinin farklı sürümlerinin veya farklı platformlarda aynı derleyicinin) genel sembolleri kökten farklı (ve dolayısıyla tamamen uyumsuz) karıştırdığı standart bir şema yoktur. yollar. Farklı C ++ derleyicilerinin aynı işlevleri nasıl karıştırdığını düşünün:

Derleyicivoid h (int)void h (int, char)void h (void)
Linux için Intel C ++ 8.0_Z1hi_Z1hic_Z1hv
HP aC ++ A.05.55 IA-64
IAR EWARM C ++ 5.4 KOL
GCC 3.x Ve daha yüksek
Clang 1.x Ve daha yüksek[3]
IAR EWARM C ++ 7.4 KOL_Z merhaba_Z hic_Z hv
GCC 2.9.xh__Fih__Fich__Fv
HP aC ++ A.03.45 PA-RISC
Microsoft Visual C ++ v6-v10 (ayrıntıları karıştırmak )? h @@ YAXH @ Z? h @@ YAXHD @ Z? h @@ YAXXZ
Dijital Mars C ++
Borland C ++ v3.1@ h $ qi@ h $ qizc@ h $ qv
OpenVMS C ++ v6.5 (ARM modu)H__XIH__XICH__XV
OpenVMS C ++ v6.5 (ANSI modu)CXX $ __ 7H__FIC26CDH77CXX $ __ 7H__FV2CB06E8
OpenVMS C ++ X7.1 IA-64CXX $ _Z1HI2DSQ26ACXX $ _Z1HIC2NP3LI4CXX $ _Z1HV0BCA19V
SunPro CC__1cBh6Fi_v___1cBh6Fic_v___1cBh6F_v_
Tru64 C ++ v6.5 (ARM modu)h__Xih__Xich__Xv
Tru64 C ++ v6.5 (ANSI modu)__7h__Fi__7h__Fic__7h__Fv
Watcom C ++ 10.6W? H $ n (i) vW? H $ n (ia) vW? H $ n () v

Notlar:

  • OpenVMS VAX ve Alpha (ancak IA-64 değil) ve Tru64'teki Compaq C ++ derleyicisinin iki ad karıştırma şeması vardır. Orijinal, standart öncesi şema ARM modeli olarak bilinir ve C ++ Açıklamalı Referans El Kitabında (ARM) açıklanan adın karıştırılmasına dayanır. Standart C ++ 'da yeni özelliklerin ortaya çıkmasıyla, özellikle şablonlar ARM şeması gittikçe daha uygunsuz hale geldi - belirli işlev türlerini kodlayamadı veya farklı işlevler için aynı şekilde karıştırılmış adlar üretti. Bu nedenle, tüm ANSI şablon özelliklerini destekleyen ancak geriye dönük uyumlu olmayan yeni "ANSI" modeli ile değiştirildi.
  • IA-64'te bir standart Uygulama İkili Arayüzü (ABI) var (bakınız Dış bağlantılar ), (diğer şeylerin yanı sıra) standart bir ad karıştırma şemasını tanımlayan ve tüm IA-64 derleyicileri tarafından kullanılan. GNU GCC 3.xayrıca, Intel dışı diğer platformlarda kullanım için bu standartta tanımlanan adı karıştırma şemasını benimsemiştir.
  • Visual Studio ve Windows SDK, programı içerir undname Bu, belirli bir karıştırılmış ad için C-stili işlev prototipini yazdırır.
  • Microsoft Windows'ta, Intel derleyicisi[4] ve Clang[5] Uyumluluk için Visual C ++ adını kullanır.
  • IAR EWARM C ++ 7.4 ARM derleyicisi için, bir işlevin adını belirlemenin en iyi yolu, assembler çıkışı açıkken derlemek ve bu şekilde oluşturulan ".s" dosyasındaki çıktıya bakmaktır.

C ++ 'dan bağlanırken C sembollerinin işlenmesi

Yaygın C ++ deyiminin işi:

#ifdef __cplusplus dış "C" {#endif    /* ... */#ifdef __cplusplus}#endif

bir C derleyicisinin yapacağı gibi, içindeki sembollerin "yönetilmemiş" olduğundan emin olmaktır - derleyicinin, bir C derleyicisinin yapacağı gibi isimleri düzeltilmemiş bir ikili dosya yayınlaması. C dili tanımları yönetilmediğinden, C ++ derleyicisinin bu tanımlayıcılara yapılan başvuruları karıştırmaktan kaçınması gerekir.

Örneğin, standart dizeler kitaplığı, <string.h>, genellikle şuna benzer bir şey içerir:

#ifdef __cplusplusdış "C" {#endifgeçersiz *memset (geçersiz *, int, size_t);kömür *strcat (kömür *, sabit kömür *);int   strcmp (sabit kömür *, sabit kömür *);kömür *strcpy (kömür *, sabit kömür *);#ifdef __cplusplus}#endif

Bu nedenle, aşağıdaki gibi kodlar:

Eğer (strcmp(argv[1], "-x") == 0)     strcpy(a, argv[2]);Başka     memset (a, 0, boyutu(a));

doğru, unmangled kullanır strcmp ve memset. Eğer extern "C" kullanılmamış olsaydı, (SunPro) C ++ derleyicisi şuna eşdeğer kod üretirdi:

Eğer (__1cGstrcmp6Fpkc1_i_(argv[1], "-x") == 0)     __1cGstrcpy6Fpcpkc_0_(a, argv[2]);Başka     __1cGmemset6FpviI_0_ (a, 0, boyutu(a));

Bu semboller C çalışma zamanı kitaplığında bulunmadığından (Örneğin. libc), bağlantı hataları ortaya çıkar.


C ++ 'da standartlaştırılmış ad değiştirme

Görünüşe göre C ++ dilinde standartlaştırılmış ad değiştirme, derleyici uygulamaları arasında daha fazla birlikte çalışabilirliğe yol açacaktır. Bununla birlikte, böyle bir standardizasyon kendi başına C ++ derleyicisinin birlikte çalışabilirliğini garanti etmek için yeterli olmayacaktır ve hatta birlikte çalışabilirliğin mümkün ve olmadığında güvenli olduğu konusunda yanlış bir izlenim yaratabilir. İsim değiştirme birkaç taneden sadece biridir uygulama ikili arabirimi (ABI) bir C ++ uygulamasıyla karar verilmesi ve gözlemlenmesi gereken ayrıntılar. Gibi diğer ABI yönleri istisna işleme, sanal masa düzen, yapı ve yığın çerçevesi dolgu malzemesi, vb. ayrıca farklı C ++ uygulamalarının uyumsuz olmasına neden olur. Ayrıca, belirli bir karıştırma biçimini gerektirmek, uygulama sınırlarının (örneğin, sembollerin uzunluğu) belirli bir karıştırma şemasını dikte ettiği sistemler için sorunlara neden olabilir. Standartlaştırılmış gereksinim ismin karıştırılması aynı zamanda karıştırmanın hiç gerekli olmadığı bir uygulamayı da engelleyecektir - örneğin, C ++ dilini anlayan bir bağlayıcı.

C ++ standardı bu nedenle ad değiştirme işlemini standartlaştırmaya çalışmaz. Aksine, Açıklamalı C ++ Referans Kılavuzu (Ayrıca şöyle bilinir KOL, ISBN  0-201-51459-1Bölüm 7.2.1c), ABI'nın diğer yönleri uyumsuz olduğunda bağlanmayı önlemek için farklı karıştırma planlarının kullanımını aktif olarak teşvik eder.

Yine de, yukarıdaki bölümde detaylandırıldığı üzere bazı platformlarda[6] tam C ++ ABI, ad değiştirme dahil olmak üzere standartlaştırılmıştır.

C ++ adı ezmenin gerçek dünyadaki etkileri

Çünkü C ++ sembolleri rutin olarak DLL ve paylaşılan nesne dosyalara bakıldığında, ad değiştirme şeması yalnızca derleyicinin iç meselesi değildir. Farklı derleyiciler (veya birçok durumda aynı derleyicinin farklı sürümleri), bu tür ikili dosyaları farklı isim süsleme şemaları altında üretir; yani, derleyiciler kitaplığı oluşturmak için kullanılırsa ve onu kullanan program farklı şemalar kullanırsa, semboller sıklıkla çözülmez. Örneğin, birden çok C ++ derleyicisinin kurulu olduğu bir sistem (örneğin, GNU GCC ve işletim sistemi satıcısının derleyicisi), C ++ Kitaplıklarını Artırın, birden çok kez derlenmesi gerekir (bir kez GCC için ve bir kez satıcı derleyicisi için).

Uyumsuz nesne kodları üreten derleyicilerin (örneğin sınıflar ve istisnalarla ilgili farklı ABI'lere dayalı kodlar) farklı ad karıştırma şemaları kullanması güvenlik açısından iyidir. Bu, bu uyumsuzlukların, yazılımı çalıştırırken değil, bağlantı aşamasında tespit edilmesini garanti eder (bu, belirsiz hatalara ve ciddi kararlılık sorunlarına yol açabilir).

Bu nedenle, ad süslemesi, C ++ ile ilgili tüm uygulamaların önemli bir yönüdür. ABI.

C ++ filt ile ayrıştırın

$ c ++ filt -n _ZNK3MapI10StringName3RefI8GDScriptE10ComparatorIS0_E16DefaultAllocatorE3hasERKS0_Map , Comparator , DefaultAllocator> :: has (StringName const &) const

Yerleşik GCC ABI aracılığıyla ayırma

#Dahil etmek <stdio.h>#Dahil etmek <stdlib.h>#Dahil etmek <cxxabi.h>int ana() {	sabit kömür *mangled_name = "_ZNK3MapI10StringName3RefI8GDScriptE10ComparatorIS0_E16DefaultAllocatorE3hasERKS0_";	int statü = -1;	kömür *demangled_name = abi::__cxa_demangle(mangled_name, BOŞ, BOŞ, &statü);	printf("Demanged:% s n", demangled_name);	Bedava(demangled_name);	dönüş 0;}

Çıktı:

Demangled: Map , Comparator , DefaultAllocator> :: has (StringName const &) const

Java

Java'da imza Bir yöntemin veya sınıfın, adı ve yöntem bağımsız değişkenlerinin türlerini ve uygun olduğu durumlarda dönüş değerini içerir. İmzaların formatı, dil, derleyici ve .class dosya formatı birlikte tasarlandığından (ve baştan itibaren akılda nesne yönelimi ve evrensel birlikte çalışabilirliğe sahip olduğundan) belgelenmiştir.

İç ve anonim sınıflar için benzersiz isimler oluşturma

Anonim sınıfların kapsamı üst sınıfları ile sınırlıdır, bu nedenle derleyicinin, aynı isimde (iç veya değil) aynı ad alanına sahip diğer sınıfların bulunduğu durumlarda çakışmayı önlemek için iç sınıf için "nitelikli" bir genel ad üretmesi gerekir. Benzer şekilde, anonim sınıflar da kendileri için oluşturulmuş "sahte" genel adlara sahip olmalıdır (anonim sınıf kavramı çalışma zamanında değil, yalnızca derleyicide var olduğundan). Yani, aşağıdaki java programını derlemek

halka açık sınıf foo {    sınıf bar {        halka açık int x;    }    halka açık geçersiz zark () {        Nesne f = yeni Nesne () {            halka açık Dize toString() {                dönüş "Merhaba";            }        };    }}

üç üretecek .sınıf Dosyalar:

  • foo.class, ana (dış) sınıfı içeren foo
  • foo $ bar.class, adlandırılmış iç sınıfı içeren foo.bar
  • foo $ 1. sınıf, anonim iç sınıfı içeren (yerelden yönteme foo.zark)

Tüm bu sınıf isimleri geçerlidir (JVM belirtiminde $ sembollerine izin verildiğinden) ve bu isimler derleyicinin oluşturması için "güvenlidir", çünkü Java dili tanımı normal java sınıfı tanımlarında $ sembollerinin kullanılmamasını tavsiye eder.

Java'da ad çözümlemesi, çalışma zamanında daha da karmaşıktır. tam nitelikli sınıf adları yalnızca belirli bir sınıf yükleyici örnek. Sınıf yükleyiciler hiyerarşik olarak sıralanır ve JVM'deki her İş Parçacığı bir bağlam sınıfı yükleyiciye sahiptir, bu nedenle iki farklı sınıf yükleyici örneğinin aynı ada sahip sınıflar içerdiği durumlarda, sistem önce kök (veya sistem) sınıf yükleyicisini kullanarak sınıfı yüklemeye çalışır. ve sonra hiyerarşiden bağlam sınıfı yükleyiciye gider.

Java Yerel Arayüzü

Java'nın yerel yöntem desteği, Java dil programlarının başka bir dilde (genellikle C veya C ++) yazılmış programları çağırmasına olanak tanır. Burada, hiçbiri özellikle standart bir şekilde uygulanmayan iki ad çözümleme endişesi vardır:

  • JVM'den yerel ad çevirisine - Oracle şemasını herkese açık hale getirdiğinden bu daha kararlı görünüyor.[7]
  • Normal C ++ adı değiştirme - yukarıya bakın.

Python

İçinde Python, karıştırma, onlara iki önde gelen alt çizgi ve birden fazla alt çizgi olmayan bir ad verilerek belirtilen "özel" sınıf üyeleri için kullanılır. Örneğin, __şey olacağı gibi ezilecek ___şey ve __şey_, fakat __şey__ ve __şey___ olmayacak. Python'un çalışma zamanı bu tür üyelere erişimi kısıtlamaz; karıştırma, yalnızca türetilmiş bir sınıf aynı ada sahip bir üye tanımladığında ad çakışmalarını önler.

İsim karıştırılmış özniteliklerle karşılaşıldığında, Python bu isimleri başına tek bir alt çizgi ve çevreleyen sınıfın adını ekleyerek dönüştürür, örneğin:

>>> sınıf Ölçek:...     def __mangled_name(kendini):...         geçmek...     def normal_name(kendini):...         geçmek>>> t = Ölçek()>>> [attr için attr içinde dir(t) Eğer "isim" içinde attr]['_Test__mangled_name', 'normal_name']

Pascal

Borland'ın Turbo Pascal / Delphi serisi

Pascal'da adların karışmasını önlemek için şunu kullanın:

ihracat  myFunc isim 'myFunc',  myProc isim 'myProc';

Ücretsiz Pascal

Ücretsiz Pascal destekler işlevi ve operatörün aşırı yüklenmesi, bu nedenle bu özellikleri desteklemek için ad karıştırmayı da kullanır. Öte yandan, Free Pascal, başka bir dille oluşturulan harici modüllerde tanımlanan sembolleri çağırabilir ve kendi sembollerini başka bir dil tarafından çağrılmak üzere ihraç edebilir. Daha fazla bilgi için danışın Bölüm 6.2 ve 7.1 nın-nin Free Pascal Programcı Kılavuzu.

Fortran

İsim değiştirme de gereklidir Fortran derleyiciler, aslında dil büyük / küçük harfe duyarlı değil. Daha sonra, eklenmesi nedeniyle dilin evriminde daha fazla karıştırma gereksinimleri getirildi. modüller ve Fortran 90 standardındaki diğer özellikler. Özellikle vaka bozma, Fortran kütüphanelerini aramak için ele alınması gereken yaygın bir sorundur. LAPACK, diğer dillerden, örneğin C.

Durum duyarsızlığı nedeniyle, bir alt yordamın veya işlevin adı FOO her durumda aynı şekilde bağlanması için derleyici tarafından standart bir duruma ve biçime dönüştürülmelidir. Farklı derleyiciler bunu çeşitli şekillerde uygulamıştır ve hiçbir standardizasyon gerçekleşmemiştir. AIX ve HP-UX Fortran derleyicileri tüm tanımlayıcıları küçük harfe dönüştürür fooiken Cray ve Unico'lar Fortran derleyicileri, tanımlayıcıları tümü büyük harfe dönüştürdü FOO. GNU g77 derleyici, tanımlayıcıları küçük harfe ve bir alt çizgiye dönüştürür foo_, tanımlayıcıların zaten bir alt çizgi içermesi dışında FOO_BAR eklenen iki alt çizgi var foo_bar__tarafından oluşturulan bir konvansiyonun ardından f2c. Dahil olmak üzere diğer birçok derleyici SGI 's IRIX derleyiciler GNU Fortran, ve Intel Fortran derleyicisi (Microsoft Windows dışında), tüm tanımlayıcıları küçük harfe ve alt çizgiye (foo_ ve foo_bar_, sırasıyla). Microsoft Windows'ta, Intel Fortran derleyicisi varsayılan olarak alt çizgi olmadan büyük harfe ayarlanır.[8]

Fortran 90 modüllerindeki tanımlayıcılar daha fazla karıştırılmalıdır çünkü aynı prosedür adı farklı modüllerde ortaya çıkabilir. Fortran 2003 Standardı, modül prosedür adlarının diğer harici sembollerle çakışmamasını gerektirdiğinden,[9] derleyiciler, modül adını ve yordam adını arada belirgin bir işaretçi kullanma eğilimindedir. Örneğin:

modül m içerirtamsayı işlevi beş()      beş = 5   son işlev beşson modül m

Bu modülde, fonksiyonun adı şu şekilde karıştırılacaktır: __m_MOD_five (örneğin, GNU Fortran), m_MP_five_ (ör. Intel’in ifortu), m.five_ (ör. Oracle'ın sun95) vb. Fortran bir prosedürün adının aşırı yüklenmesine izin vermediğinden, genel arayüz blokları ve bunun yerine genel tipe bağlı prosedürler, karıştırılmış adların argümanlar hakkında ipuçları içermesine gerek yoktur.

Fortran 2003 BIND seçeneği, gösterildiği gibi derleyici tarafından yapılan herhangi bir ad değiştirme işlemini geçersiz kılar yukarıda.

Pas, paslanma

İşlev adları varsayılan olarak karıştırılır Pas, paslanma. Ancak bu, tarafından devre dışı bırakılabilir. # [no_mangle] function özelliği. Bu özellik, işlevleri C, C ++ veya Objective-C'ye dışa aktarmak için kullanılabilir.[10] Ek olarak, #[Başlat] function özniteliği veya # [no_main] sandık niteliği, kullanıcının program için C tarzı bir giriş noktası tanımlamasına izin verir.[11]

Rust, derleme sırasında seçilebilen birçok sembol karıştırma şeması versiyonunu kullanmıştır. -Z sembolünü karıştıran versiyon seçeneği. Aşağıdaki düzenleyiciler tanımlanmıştır:

  • miras Itanium IA-64 C ++ ABI'yi temel alan C ++ tarzı bir karıştırma. Semboller şununla başlar _ZNve dosya adı karmaları, belirsizliği gidermek için kullanılır. Rust 1.9'dan beri kullanılmaktadır.[12]
  • s0 Rust için değişikliklerle eski şemanın geliştirilmiş bir sürümü. Semboller şununla başlar _R. Polimorfizm kodlanabilir. Fonksiyonların kodlanmış dönüş türleri yoktur (Rust'ta aşırı yükleme yoktur). Unicode adları değiştirilmiş kullanır zayıf kod. Sıkıştırma (geri başvuru) bayt tabanlı adresleme kullanır. Rust 1.37'den beri kullanılmaktadır.[13]

Rust'ta örnekler verilmiştir sembol isimleri testleri.[14]

Amaç-C

Esasen iki yöntem biçimi vardır: Amaç-C, sınıf ("statik") yöntemi, ve örnek yöntemi. Objective-C'deki bir yöntem bildirimi aşağıdaki biçimdedir:

+ (dönüş tipi) isim0:parametre0 isim1:parametre1 ...– (dönüş tipi) isim0:parametre0 isim1:parametre1 ...

Sınıf yöntemleri + ile gösterilir, örnek yöntemler - kullanır. Tipik bir sınıf yöntemi bildirimi şu şekilde görünebilir:

+ (İD) initWithX: (int) numara andY: (int) numara;+ (İD) yeni;

Aşağıdaki gibi görünen örnek yöntemleri ile:

- (İD) değer;- (İD) setValue: (İD) yeni değer;

Bu yöntem bildirimlerinin her birinin belirli bir dahili temsili vardır. Derlendiğinde, her yöntem, sınıf yöntemleri için aşağıdaki şemaya göre adlandırılır:

_c_Sınıf_isim0_isim1_ ...

ve bu örneğin yöntemler:

_ben_Sınıf_isim0_isim1_ ...

Objective-C sözdizimindeki iki nokta üst üste alt çizgilere çevrilir. Dolayısıyla, Objective-C sınıfı yöntemi + (İD) initWithX: (int) numara andY: (int) numara;eğer aitse Nokta sınıf şu şekilde çevrilir _c_Point_initWithX_andY_ve örnek yöntemi (aynı sınıfa ait) - (İD) değer; tercüme ederdi _i_Point_value.

Bir sınıfa ait yöntemlerin her biri bu şekilde etiketlenir. Bununla birlikte, bir sınıfın yanıt verebileceği bir yöntemi aramak için, tüm yöntemler bu şekilde temsil edilirse sıkıcı olacaktır. Yöntemlerin her birine benzersiz bir sembol (bir tamsayı gibi) atanır. Böyle bir sembol, seçici. Objective-C'de, seçiciler doğrudan yönetilebilir - bunlar Objective-C'de belirli bir türe sahiptir - SEL.

Derleme sırasında, metinsel gösterimi eşleyen bir tablo oluşturulur. _i_Point_value, seçicilere (bir tür verilir SEL). Seçicileri yönetmek, bir yöntemin metinsel temsilini değiştirmekten daha etkilidir. Bir seçicinin ait olduğu sınıfla değil, yalnızca bir yöntemin adıyla eşleştiğini unutmayın - farklı sınıflar, aynı ada sahip bir yöntemin farklı uygulamalarına sahip olabilir. Bu nedenle, bir yöntemin uygulamalarına da belirli bir tanımlayıcı verilir, bunlar uygulama işaretçileri olarak bilinir ve ayrıca bir tür verilir, IMP.

Mesaj gönderimleri, derleyici tarafından İD objc_msgSend (İD alıcı, SEL seçici, ...) işlev veya kuzenlerinden biri, nerede alıcı mesajın alıcısıdır ve SEL aranacak yöntemi belirler. Her sınıfın, seçicileri uygulamalarına eşleyen kendi tablosu vardır - uygulama işaretçisi, yöntemin gerçek uygulamasının bellekte nerede bulunduğunu belirtir. Sınıf ve örnek yöntemleri için ayrı tablolar vardır. Depolamanın dışında SEL -e IMP arama tabloları, işlevler esasen anonimdir.

SEL bir seçicinin değeri sınıflar arasında değişmez. Bu olanak sağlar çok biçimlilik.

Objective-C çalışma zamanı, yöntemlerin bağımsız değişken ve dönüş türleri hakkındaki bilgileri tutar. Ancak, bu bilgiler yöntemin adının bir parçası değildir ve sınıftan sınıfa değişebilir.

Objective-C desteklemediğinden ad alanları, sınıf adlarının (üretilen ikili dosyalarda semboller olarak görünen) karıştırılmasına gerek yoktur.

Swift

Swift, işlevler (ve daha fazlası) hakkındaki meta verileri, bunlara atıfta bulunan karıştırılmış sembollerde tutar. Bu meta veriler, işlevin adını, özniteliklerini, modül adını, parametre türlerini, dönüş türünü ve daha fazlasını içerir. Örneğin:

Bir yöntemin karıştırılmış adı func hesapla (x: int) -> int bir Sınıfım modüldeki sınıf Ölçek dır-dir _TFC4test7MyClass9calculatefS0_FT1xSi_Si, 2014 Swift için. Bileşenler ve anlamları aşağıdaki gibidir:[15]

  • _T: Tüm Swift sembolleri için önek. Her şey bununla başlayacak.
  • F: Kıvrılmamış fonksiyon.
  • C: Bir sınıfın işlevi. (yöntem)
  • 4test: Ön ek uzunluğa sahip modül adı.
  • 7 Sınıfım: Fonksiyonun ait olduğu sınıf adı, yine, önceden belirlenmiş uzunlukta.
  • 9hesapla: İşlev adı.
  • f: Function özelliği. Bu durumda, normal bir işlev olan "f" dir.
  • S0: İlk parametrenin türünü (yani sınıf örneği) tür yığınındaki ilk (burada Sınıfım yuvalanmış değildir ve bu nedenle 0 dizinine sahiptir).
  • _FT: Bu, işlevin parametre dizisi için tür listesini başlatır.
  • 1x: Fonksiyonun ilk parametresinin harici adı.
  • Si: Yerleşik Swift türünü gösterir Şablon: Swift.Int ilk parametre için.
  • _Si: Dönüş türü; tekrar Şablon: Swift.Int.

Swift 4.0'dan bu yana sürümler resmi olarak belgelenmiştir. Itanium ile bazı benzerliklerini koruyor.[16]

Ayrıca bakınız

Referanslar

  1. ^ "Uygulama İkili Arayüzü - D Programlama Dili". dlang.org. Alındı 2020-05-19.
  2. ^ Rainer, Schuetze. "D'nin Yeni Çıkmış Adı Mangling". D Blog. Alındı 2020-05-19.
  3. ^ Clang - Özellikler ve Hedefler: GCC Uyumluluğu, 15 Nisan 2013
  4. ^ JBIntel_deleted_06032015. "Intel Compiler ve VC Compiler arasındaki OBJ farklılıkları". software.intel.com.
  5. ^ "MSVC uyumluluğu". Alındı 13 Mayıs 2016.
  6. ^ "Itanium C ++ ABI, Bölüm 5.1 Dış Adlar (a.k.a. Mangling)". Alındı 16 Mayıs 2016.
  7. ^ "Tasarıma Genel Bakış". docs.oracle.com.
  8. ^ "Karma Dil Sorunlarının Özeti". Intel Fortran Compiler 15.0 Kullanıcı ve Başvuru Kılavuzu. Intel Kurumu. Alındı 17 Kasım 2014.
  9. ^ https://software.intel.com/en-us/node/510637
  10. ^ "Yabancı İşlev Arayüzü # C'den Rust kodunu Çağırma". Rust Kılavuzu. rust-lang.org. Alındı 13 Mayıs 2016.
  11. ^ "Stdlib yok". Rust Kılavuzu. rust-lang.org. Alındı 13 Mayıs 2016.
  12. ^ "rust / src / librustc_codegen_utils / symbol_names / legacy.r.rs at 57e1da59cd0761330b4ea8d47b16340a78eeafa9 · rust-lang / rust · GitHub".
  13. ^ "Pas Sembolü Mangling". Rust RFC Kitabı.
  14. ^ "Rust 1.42.0: src / test / ui / simge adları". GitHub. Alındı 20 Mart 2020.
  15. ^ "mikeash.com: Cuma Soru-Cevap 2014-08-15: Swift Adı Mangling". mikeash.com.
  16. ^ "apple / swift: mangling.rst". GitHub.

Dış bağlantılar