Кіріспе
Компилятор құрастырудағы техника Компилятор құрастыруда атауды бұрмалау (оған атауды безендіру делінеді) – көптеген заманауи бағдарламалау тілдерінде бағдарламалық элементтердің бірегей атауларын анықтау қажеттілігінен туындаған түрлі мәселелерді шешуге арналған техника. Ол функцияның, құрылымның, кластың немесе басқа да дерек типінің атына қосымша ақпаратты енгізуге мүмкіндік береді, соның арқылы компилятордан байланыстырушыға (линкерге) көбірек семантикалық ақпаратты жіберуге болады. Атауды бұрмалау қажеттілігі тіл әртүрлі атау кеңістіктерінде (әдетте модуль, класс немесе нақты атау кеңістігі директивасымен анықталатын) немесе әртүрлі типтік қолтаңбалары бар бірдей идентификатормен бірнеше элементті атауға рұқсат бергенде туындайды (мысалы, функцияның жүктемесі). Мұндай жағдайларда әрбір қолтаңба машиналық кодта әртүрлі, арнайы шақыру конвенциясын қажет ететін болғандықтан бұл қажет. Компиляторлар жасаған кез келген объектілік код әдетте басқа объектілік кодтармен (сол немесе басқа компилятор жасаған) байланыстырушы бағдарламасы арқылы байланыстырылады. Байланыстырушыға әрбір бағдарламалық элемент туралы көптеген ақпарат қажет. Мысалы, функцияны дұрыс байланыстыру үшін оның аты, аргументтердің саны мен түрлері және т.б. керек. 1970 жылдардағы C сияқты қарапайым бағдарламалау тілдері субпрограммаларды тек аты бойынша ғана ажыратты, параметрлер мен қайтару түрлері сияқты басқа ақпаратты ескермеді. Кейінірек пайда болған C++ сияқты тілдер, функцияның параметрлерінің түрлері, қайтару түрі және шақыру конвенциясы сияқты "тең" деп есептелуі үшін процедураларға қатаң талаптар қойды. Бұл талаптар әдісті жүктеуге және кейбір қателерді анықтауға (мысалы, әртүрлі бастапқы код файлдарын компиляциялау кезінде функцияның әртүрлі анықтамасын пайдалану) мүмкіндік береді. Бұл қатаң талаптар қолданыстағы бағдарламалау құралдарымен және конвенциялармен үйлесімді болуы керек еді. Сондықтан, қосымша талаптар символдың атына енгізілді, өйткені дәстүрлі байланыстырушы символ туралы тек осы ақпаратты ғана білді. Атауды бұрмалаудың тағы бір мақсаты – қолтаңбаға байланысты емес, қосымша өзгерістерді анықтау, мысалы, функцияның тазалығын немесе оның ерекшелік тудыру мүмкіндігін немесе қоқыс жинауды іске қосуын анықтау. D тілі мұны істейтін тілдің мысалы. Бұл қателерді тексерудің қарапайым түрі. Мысалы, екі функция бір объектілік файлға компиляциялануы мүмкін, бірақ содан кейін олардың қолтаңбалары өзгереді және оларды шақыратын басқа кодты компиляциялау үшін қолданылады. Байланыс кезінде байланыстырушы функцияның жоқтығын анықтап, қате туралы хабар береді. Сол сияқты, байланыстырушы қайтару түрінің өзгергенін анықтай алмайды және қате қайтарады. Әйтпесе, үйлесімсіз шақыру конвенциялары қолданылуы мүмкін, бұл көбінесе дұрыс емес нәтижеге немесе бағдарламаның құлауына әкеледі. Бұрмалау шақыру процесінің барлық егжей-тегжейін қамтымайды. Мысалы, ол құрылымның немесе кластың дерек мүшелерінің өзгеруі сияқты қателерді толығымен болдырмайды. Мысалы, бір нысан файлына компиляциялануы мүмкін, содан кейін оның анықтамасы өзгереді және шақыруды компиляциялау үшін қолданылады. Мұндай жағдайларда компилятор әдетте басқа шақыру конвенциясын қолданады, бірақ екі жағдайда да бұрмалау бірдей атауға әкеледі, сондықтан байланыстырушы бұл мәселені анықтай алмайды, нәтижесінде ақау, деректердің бұзылуы немесе жадтың бұзылуы болады.
In compiler construction, name mangling (also called name decoration) is a technique used to solve various problems caused by the need to resolve unique names for programming entities in many modern programming languages. It provides means to encode added information in the name of a function, structure, class or another data type, to pass more semantic information from the compiler to the linker. The need for name mangling arises where a language allows different entities to be named with the same identifier as long as they occupy a different namespace (typically defined by a module, class, or explicit namespace directive) or have different type signatures (such as in function overloading). It is required in these uses because each signature might require different, specialized calling convention in the machine code. Any object code produced by compilers is usually linked with other pieces of object code (produced by the same or another compiler) by a type of program called a linker. The linker needs a great deal of information on each program entity. For example, to correctly link a function it needs its name, the number of arguments and their types, and so on. The simple programming languages of the 1970s, like C, only distinguished subroutines by their name, ignoring other information including parameter and return types. Later languages, like C++, defined stricter requirements for routines to be considered "equal", such as the parameter types, return type, and calling convention of a function. These requirements enable method overloading and detection of some bugs (such as using different definitions of a function when compiling different source code files). These stricter requirements needed to work with extant programming tools and conventions. Thus, added requirements were encoded in the name of the symbol, since that was the only information a traditional linker had about a symbol. Another use of name mangling is for detecting added non signature related changes, such as function purity, or whether it can potentially throw an exception or trigger garbage collection. An example of a language doing this is D. These are more of a simplified error checking. For example, functions and could be compiled into one object file, but then their signatures changed to and used to compile other source calling it. At link time the linker will detect there is no function and return an error. Similarly, the linker will not be able to detect that the return type of is different, and return an error. Otherwise, incompatible calling conventions would be used, and most likely produce the wrong result or crash the program. Mangling doesn't usually capture every detail of the calling process. For example, it doesn't fully prevent errors like changes of data members of a struct or class. For example, could be compiled into one object file, then the definition for changed to be and used in the compiling of a call to In such cases, the compiler will usually use a different calling convention, but in both cases will mangle to the same name, so the linker will not detect this problem, and the result will usually be a crash or data or memory corruption at runtime.
C++ тілінде
C++ компиляторлары атауларды бұрмалауды ең көп қолданады. Алғашқы C++ компиляторлары C бастапқы кодына аудармашы ретінде жасалған, содан кейін C компиляторы оны объектілік кодқа компиляциялаған; осы себепті символ атаулары C идентификаторларының ережелеріне сәйкес болуы тиіс болды. Кейіннен, тікелей машиналық кодты немесе құрастыру тілін құратын компиляторлар пайда болғанмен де, жүйенің байланыстырғышы (линкері) көбінесе C++ символдарымен жұмыс істемейтін, сондықтан бұрмалау қажеттігі сақталды. C++ тілінде стандартты безендіру схемасы белгіленбеген, сондықтан әр компилятор өзінің жеке схемасын қолданады. C++ тілінде сыныптар, шаблонды параметрлер, атау кеңістіктері және операторларды жүктеу сияқты күрделі тілдік мүмкіндіктер де бар, олар символдардың мағынасын контекстке немесе қолданылуына қарай өзгертеді. Осы мүмкіндіктер туралы қосымша деректерді символдың атын бұрмалау арқылы (безендіру арқылы) ажыратуға болады. Мұндай мүмкіндіктерге арналған атау бұрмалау жүйелері компиляторлар арасында стандартталмағандықтан, көптеген байланыстырғыштар әртүрлі компиляторлар жасаған объектілік кодты байланыстыра алмайды.
C++ тілінде стандартталған атауды бұрмалау
C++ тіліндегі стандартталған атауларды бұрмалау компиляторлардың өзара іс-қимылын жақсартуға мүмкіндік берер еді. Алайда, мұндай стандарттау ғана C++ компиляторларының өзара іс-қимылына кепілдік беруге жеткіліксіз, тіпті өзара іс-қимыл мүмкін және қауіпсіз емес деген жалған түйін тудыруы мүмкін. Атауды бұрмалау – C++ іске асырылуында шешіліп, сақталуы тиіс қосымша екілік интерфейсінің (ABI) көптеген ерекшеліктерінің бірі ғана. Қосымшаны өңдеу, виртуалды кестелердің орналасуы, құрылым және стек кадрларын толтыру сияқты ABI-дың басқа да аспектілері әртүрлі C++ іске асырылуларының үйлесімсіздігіне себеп болады. Бұған қоса, белгілі бір бұрмалау нысанын талап ету, іске асыру шектері (мысалы, символдардың ұзындығы) белгілі бір бұрмалау схемасын қажет ететін жүйелерде қиындықтар тудыруы мүмкін. Атауды бұрмалаудың стандартталған талабы бұрмалау мүлдем қажет емес жағдайдағы іске асыруға кедерілдіреді – мысалы, C++ тілін түсінетін байланыстырушы. Сондықтан C++ стандарты атауларды бұрмалауды стандарттауға тырыспайды. Керісінше, C++ Annotated Reference Manual (ARM, 7.2.1c бөлімі деп те аталады) ABI-дың басқа аспектілері үйлеспесе, байланыстыруды болдырмау үшін әртүрлі бұрмалау схемаларын қолдануға белсенді түрде шақырады. Дегенмен, жоғарыда айтылғандай, кейбір платформаларда толық C++ ABI, соның ішінде атауларды бұрмалау стандартталған.
C++ атауының бұзылуының нақты әсерлері
C++ символдары DLL және ортақ нысан файлдарынан әдетте экспортталатындықтан, атауды өзгерту схемасы компилятордың ішкі мәселесі ғана емес. Әртүрлі компиляторлар (немесе бір компилятордың әртүрлі нұсқалары, көбінесе) осындай екілік файлдарды әртүрлі атау безендіру схемаларымен жасайды, яғни кітапхананы құру үшін қолданылған компиляторлар мен оны пайдаланатын бағдарлама әртүрлі схемаларды қолданса, символдар көбінесе анықталмайды. Мысалы, бірнеше C++ компиляторы орнатылған жүйе (мысалы, GNU GCC және операциялық жүйе жеткізушісінің компиляторы) Boost C++ кітапханаларын орнатқысы келсе, оларды бірнеше рет құрастыру керек (бір рет GCC үшін және бір рет жеткізушінің компиляторы үшін). Қауіпсіздік тұрғысынан, үйлесімсіз объектілік кодтарды (мысалы, сыныптар мен өте жағдайларға қатысты әртүрлі ABI негізіндегі кодтарды) жасайтын компиляторлар әртүрлі атауды өзгерту схемаларын пайдалануы тиімді. Бұл үйлесімсіздіктер бағдарламаны орындау кезінде емес, байланыс кезеңінде анықталады дегенге кепілдік береді (әйтпесе, түсініксіз қателер мен тұрақсыздық мәселелеріне әкелуі мүмкін). Осы себепті атауды безендіру кез келген C++ байланысты ABI-дың маңызды аспектісі болып табылады. Кейде, әсіресе үлкен және күрделі код базаларында, линкер қате хабарламасында шығарылған өзгертілген атауды бастапқы кодтағы сәйкес келетін таңба/айнымалы атауымен сәйкестендіру қиын немесе мүмкін емес болуы мүмкін. Бұл мәселе құрастырушы немесе тестілеуші инженерлерге, тіпті бір компилятор мен линкер қолданылса да, қажетті бастапқы файлдарды анықтауды өте қиын етеді. Деманглерлер (оның ішінде линкер қателерін хабарлау механизмдері) кейде көмектеседі, бірақ атауды өзгерту механизмі маңызды ажырату ақпаратын жоюы мүмкін.
Жава
Java-да әдістің немесе кластың қолтаңбасы оның атын, әдіс аргументтерінің түрлерін және қолданылған жағдайда қайтарылатын мәнін қамтиды. Тіл, компилятор және сынып файл форматы бірге жоспарланғандықтан қолтаңбалар форматы құжатталған (және бастапқыда объектіге бағытталғандық және әмбебап үйлесімділік ескерілген).
Java- ның жергілікті интерфейсі
Java Native Interface, Java-ның жергілікті әдістерін қолдауы, Java тіліндегі бағдарламаларға басқа тілде (әдетте C немесе C++) жазылған бағдарламаларды шақыруға мүмкіндік береді. Мұнда екі атауды анықтау мәселесі бар, екеуі де стандартталған тәсілмен іске асырылмаған:
JVM-ді жергілікті атауларға аудару – Oracle өз схемасын жариялағандықтан, бұл тұрақтырақ сияқты. C++ тіліндегі атаулардың қалыпты бұрмалануы – жоғарыда айтылғандай.
Еркін Паскаль
Free Pascal функциялар мен операторларды қайта жүктеуді қолдайды, осылайша осы мүмкіндіктерді қолдау үшін атауларды өзгертуді де пайдаланады. Екінші жағынан, Free Pascal басқа тілде жасалған сыртқы модульдерде анықталған символдарды шақыруға және басқа тілде шақырылатын өзінің символдарымен бөлісуге қабілетті. Толық ақпарат алу үшін Free Pascal Programmer's Guide нұсқаулығының 6.2 және 7.1 тарауларын қараңыз.
Қатты тотығу
Функция атаулары Rust-та әдепкі бойынша өзгертіледі. Дегенмен, бұл функция атрибуты арқылы өшірілуі мүмкін. Бұл атрибут функцияларды C, C++ немесе Objective C-ге экспорттау үшін қолданылуы мүмкін. Сонымен қатар, функция атрибуты немесе crate атрибутымен бірге, ол пайдаланушыға бағдарлама үшін C стиліндегі кіру нүктесін анықтауға мүмкіндік береді. Rust символдарды өзгерту схемаларының көптеген нұсқаларын пайдаланды, оларды компиляция уақытында опция арқылы таңдауға болады. Келесі өзгертушілер анықталды: Itanium IA 64 C++ ABI негізіндегі C++ стиліндегі өзгерту. Символдар , символымен басталады, ал файл атауының хэштері айқындық үшін қолданылады. Rust 1.9 нұсқасынан бастап қолданылады. Rust үшін өзгерістер енгізілген бұрынғы схеманың жетілдірілген нұсқасы. Полиморфизм кодталуы мүмкін. Функциялардың қайтарым түрлері кодталмайды (Rust-та функцияны жүктеу мүмкіндігі жоқ). Юникод атаулары өзгертілген punycode форматын қолданады. Сығу (кері сілтеме) байт негізіндегі адрестеуді пайдаланады. Rust 1.37 нұсқасынан бері қолданылып келеді. Мысалдар Rust тесттерінде келтірілген.
A C++ style mangling based on the Itanium IA 64 C++ ABI. Symbols begin with , and filename hashes are used for disambiguation. Used since Rust 1.9. An improved version of the legacy scheme, with changes for Rust. Symbols begin with Polymorphism can be encoded. Functions don't have return types encoded (Rust does not have overloading). Unicode names use modified punycode. Compression (backreference) use byte based addressing. Used since Rust 1.37. Examples are provided in the Rust tests.
Тез
Swift функцияларға (және одан да көп) қатысты метадеректерді оларға сілтеме жасайтын бүлінген символдарда сақтайды. Бұл метадеректер функцияның атауы, атрибуттары, модуль атауы, параметр түрлері, қайтару түрі және басқа да мәліметтерді қамтиды. Мысалы:
2014 жылғы Swift үшін модульдегі сыныптың әдісінің бүлінген атауы мынадай: . Құралымдар мен олардың мағыналары төмендегідей:
: Барлық Swift символдары үшін префикс. Барлығы осыдан басталады. : Каррисізделмеген функция. : Сыныптың функциясы, яғни әдіс. : Модуль атауы, оның ұзындығымен префикстелген. : Функцияның тиесілі болған сыныбының атауы, оның ұзындығымен префикстелген. : Функцияның атауы, оның ұзындығымен префикстелген. : Функцияның атрибуты. Бұл жағдайда ‘f’, яғни қалыпты функция. : Бірінші параметрдің түрін (яғни сынып инстанциясын) тип стегіндегі бірінші ретінде белгілейді (мұнда ұяланбағандықтан индексі 0). : Бұл функцияның параметрлік тізімінің типтер тізімін бастайды. : Функцияның бірінші параметрінің сыртқы атауы. : Бірінші параметр үшін Swift типіндегі Swift.Int екенін көрсетеді. : Қайтару түрі: қайтадан Swift.Int. Swift 4.0 нұсқаларынан бері Mangling ресми түрде құжатталған. Ол Itanium-ға қандай да бір ұқсастықты сақтайды.
: Module name, prefixed with its length. : Name of class the function belongs to, prefixed with its length. : Function name, prefixed with its length. : The function attribute. In this case ‘f’, which means a normal function. : Designates the type of the first parameter (namely the class instance) as the first in the type stack (here is not nested and thus has index 0). : This begins the type list for the parameter tuple of the function. : External name of first parameter of the function. : Indicates builtin Swift type Swift. Int for the first parameter. : The return type: again Swift. Int. Mangling for versions since Swift 4.0 is documented officially. It retains some similarity to Itanium.