завантаження...

Адреса:

місто Львів, 79020, вул. Варшавська, 193

Так‑так, щось новеньке! Та є одне але… Інформація про неоднозначність нового функціоналу, що з’явився за підсумками проведення конференції WWDC21, була захована в зауваженнях до випуску Xcode 13.

Усі програми і бібліотеки dylib, що обирають macOS 12 або iOS 15 (і ініші їхні версії) як цільову платформу розгортання, тепер використовують формат об’єднаних в ланцюжки адресних прив’язок. При цьому залучаються різні команди завантаження і дані LINKEDIT. А от самі ці програми і бібліотека не будуть запускатися чи завантажуватися на попередніх версіях ОС.

Про таке нововведення на конференції не було сказано ні слова. Та й будь‑яка документація про це відсутня. Але спробуймо розкрити його нюанси і розібратися в тому, що в Apple тепер роблять по‑іншому і яку користь це несе для додатків.

Насамперед трохи про програму, яка відповідає за запуск додатка.

dyld

Це динамічний компонувальник, що є точкою входу будь‑якого додатка і який відповідає за підготовку коду до запуску. Очевидно, що будь-яке поліпшення dyld – це відповідне зменшення витрат часу на запуск програми. Перед викликом main запускається блок статичної ініціалізації або налаштовується Виконавча Objective-C. А dyld виконує адресні прив’язки.

З чого вони складаються? З операцій переміщення і прив’язки, які змінюють показники у файлі програми. Причому роблять це так, що вони містять адреси, які залишаються актуальними і робочими під час виконання.

Як ці операції виглядають? Ось так:

% xcrun dyldinfo -rebase -bind Snapchat.app/Snapchat rebase information (from compressed dyld info): segment section address type __DATA __got 0x10748C0C8 pointer … bind information: segment section address type addend dylib symbol __DATA __const 0x107595A70 pointer 0 libswiftCore _$sSHMp

І що ж тут відбувається? Адреса 0x10748C0C8 знаходиться в __DATA / __ got. Його треба перемістити, закріпити за ним якесь постійне значення, яке так і називається «зрушення». А коли адреса 0x107595A70 знаходиться вже в __DATA / __ const і вказує на дескриптор протоколу для Hashable з libswiftCore.dylib, dyld використовує команду завантаження LC_DYLD_INFO і структуру dyld_info_command для визначення розташування та розміру переміщень, прив’язок і експортованих символів у файлі. Там відбувається парсинг даних для візуальної оцінки впливу переміщень і прив’язок на розмір двійкового коду.

Новий формат

Якщо вперше завантажити туди додаток для iOS 15, то візуалізації адресних прив’язок dyld ще не буде. Команду завантаження LC_DYLD_INFO_ONLY замінили на LC_DYLD_CHAINED_FIXUPS і LC_DYLD_EXPORTS_TRIE. Хоча експорт даних такий самий, як і був раніше.

Що ж змінилося?

Єдина зміна в iOS 15 – на дані тепер посилаються за допомогою linkedit_data_command, в якому міститься зсув першого вузла. Перевірили це, прописавши додаток на Swift для виконання парсингу двійкового коду iOS 15 і виведення кожного символу:

let bytes = (try! Data(contentsOf: url) as NSData).bytes bytes.processLoadComands { load_command, pointer in if load_command.cmd == LC_DYLD_EXPORTS_TRIE { let dataCommand = pointer.load(as: linkedit_data_command.self) bytes.advanced(by: Int(dataCommand.dataoff)).readExportTrie() } } extension UnsafeRawPointer { func readExportTrie() { var frontier = readNode(name: “”) guard !frontier.isEmpty else { return } repeat { let (prefix, offset) = frontier.removeFirst() let children = advanced(by: Int(offset)).readNode(name: prefix) for (suffix, offset) in children { frontier.append((prefix + suffix, offset)) } } while !frontier.isEmpty } // Возвращает массив дочерних узлов и их смещение func readNode(name: String) -> [(String, UInt)] { guard load(as: UInt8.self) == 0 else { // Это конечный узел print(“symbol name \(name)”) return [] } let numberOfBranches = UInt(advanced(by: 1).load(as: UInt8.self)) var mutablePointer = self.advanced(by: 2) var result = [(String, UInt)]() for _ in 0..<numberOfBranches { result.append( (mutablePointer.readNullTerminatedString(), mutablePointer.readULEB())) } return result } }

Ланцюжки прив’язок

Реальне зміна відбулася в LC_DYLD_CHAINED_FIXUPS. До iOS 15 переміщення, прив’язки і «ледачі» прив’язки зберігалися кожна в окремій таблиці. А тепер вони об’єднані в ланцюжки.

чорний iphone 4 на чорній поверхні