Кіріспе

Компилятор құрастырудағы техника Компилятор құрастыруда атауды бұрмалау (оған атауды безендіру делінеді) – көптеген заманауи бағдарламалау тілдерінде бағдарламалық элементтердің бірегей атауларын анықтау қажеттілігінен туындаған түрлі мәселелерді шешуге арналған техника. Ол функцияның, құрылымның, кластың немесе басқа да дерек типінің атына қосымша ақпаратты енгізуге мүмкіндік береді, соның арқылы компилятордан байланыстырушыға (линкерге) көбірек семантикалық ақпаратты жіберуге болады. Атауды бұрмалау қажеттілігі тіл әртүрлі атау кеңістіктерінде (әдетте модуль, класс немесе нақты атау кеңістігі директивасымен анықталатын) немесе әртүрлі типтік қолтаңбалары бар бірдей идентификатормен бірнеше элементті атауға рұқсат бергенде туындайды (мысалы, функцияның жүктемесі). Мұндай жағдайларда әрбір қолтаңба машиналық кодта әртүрлі, арнайы шақыру конвенциясын қажет ететін болғандықтан бұл қажет. Компиляторлар жасаған кез келген объектілік код әдетте басқа объектілік кодтармен (сол немесе басқа компилятор жасаған) байланыстырушы бағдарламасы арқылы байланыстырылады. Байланыстырушыға әрбір бағдарламалық элемент туралы көптеген ақпарат қажет. Мысалы, функцияны дұрыс байланыстыру үшін оның аты, аргументтердің саны мен түрлері және т.б. керек. 1970 жылдардағы C сияқты қарапайым бағдарламалау тілдері субпрограммаларды тек аты бойынша ғана ажыратты, параметрлер мен қайтару түрлері сияқты басқа ақпаратты ескермеді. Кейінірек пайда болған C++ сияқты тілдер, функцияның параметрлерінің түрлері, қайтару түрі және шақыру конвенциясы сияқты "тең" деп есептелуі үшін процедураларға қатаң талаптар қойды. Бұл талаптар әдісті жүктеуге және кейбір қателерді анықтауға (мысалы, әртүрлі бастапқы код файлдарын компиляциялау кезінде функцияның әртүрлі анықтамасын пайдалану) мүмкіндік береді. Бұл қатаң талаптар қолданыстағы бағдарламалау құралдарымен және конвенциялармен үйлесімді болуы керек еді. Сондықтан, қосымша талаптар символдың атына енгізілді, өйткені дәстүрлі байланыстырушы символ туралы тек осы ақпаратты ғана білді. Атауды бұрмалаудың тағы бір мақсаты – қолтаңбаға байланысты емес, қосымша өзгерістерді анықтау, мысалы, функцияның тазалығын немесе оның ерекшелік тудыру мүмкіндігін немесе қоқыс жинауды іске қосуын анықтау. D тілі мұны істейтін тілдің мысалы. Бұл қателерді тексерудің қарапайым түрі. Мысалы, екі функция бір объектілік файлға компиляциялануы мүмкін, бірақ содан кейін олардың қолтаңбалары өзгереді және оларды шақыратын басқа кодты компиляциялау үшін қолданылады. Байланыс кезінде байланыстырушы функцияның жоқтығын анықтап, қате туралы хабар береді. Сол сияқты, байланыстырушы қайтару түрінің өзгергенін анықтай алмайды және қате қайтарады. Әйтпесе, үйлесімсіз шақыру конвенциялары қолданылуы мүмкін, бұл көбінесе дұрыс емес нәтижеге немесе бағдарламаның құлауына әкеледі. Бұрмалау шақыру процесінің барлық егжей-тегжейін қамтымайды. Мысалы, ол құрылымның немесе кластың дерек мүшелерінің өзгеруі сияқты қателерді толығымен болдырмайды. Мысалы, бір нысан файлына компиляциялануы мүмкін, содан кейін оның анықтамасы өзгереді және шақыруды компиляциялау үшін қолданылады. Мұндай жағдайларда компилятор әдетте басқа шақыру конвенциясын қолданады, бірақ екі жағдайда да бұрмалау бірдей атауға әкеледі, сондықтан байланыстырушы бұл мәселені анықтай алмайды, нәтижесінде ақау, деректердің бұзылуы немесе жадтың бұзылуы болады.

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 тесттерінде келтірілген.

Тез

Swift функцияларға (және одан да көп) қатысты метадеректерді оларға сілтеме жасайтын бүлінген символдарда сақтайды. Бұл метадеректер функцияның атауы, атрибуттары, модуль атауы, параметр түрлері, қайтару түрі және басқа да мәліметтерді қамтиды. Мысалы:

2014 жылғы Swift үшін модульдегі сыныптың әдісінің бүлінген атауы мынадай: . Құралымдар мен олардың мағыналары төмендегідей:

: Барлық Swift символдары үшін префикс. Барлығы осыдан басталады. : Каррисізделмеген функция. : Сыныптың функциясы, яғни әдіс. : Модуль атауы, оның ұзындығымен префикстелген. : Функцияның тиесілі болған сыныбының атауы, оның ұзындығымен префикстелген. : Функцияның атауы, оның ұзындығымен префикстелген. : Функцияның атрибуты. Бұл жағдайда ‘f’, яғни қалыпты функция. : Бірінші параметрдің түрін (яғни сынып инстанциясын) тип стегіндегі бірінші ретінде белгілейді (мұнда ұяланбағандықтан индексі 0). : Бұл функцияның параметрлік тізімінің типтер тізімін бастайды. : Функцияның бірінші параметрінің сыртқы атауы. : Бірінші параметр үшін Swift типіндегі Swift.Int екенін көрсетеді. : Қайтару түрі: қайтадан Swift.Int. Swift 4.0 нұсқаларынан бері Mangling ресми түрде құжатталған. Ол Itanium-ға қандай да бір ұқсастықты сақтайды.