Comments 16
Казалось бы, это уже все известно, но приятно прочитать структурированную статью со ссылками. Спасибо.
Например, мы не разобрались с возвратом результата из вызываемых методов
Хорошо бы коснуться type encoding у методов классов. Как это работает и зачем оно вообще нужно. Потому как на уровне асссемблера это все не нужно. Есть calling conventions, они все сделают — все методы используют стандартные ARM calling conventions, если говорить об iOS. С переопределением методов очень просто передать в метод аргументы совершенно не тех типов, либо вообще передать меньше, чем надо. Получишь или UB, или segmentation fault. Поэтому интересно, что с этой информацией делает рантайм.
Единственное место, где реально нужно знать type encoding, это NSInvocation, где аргументы передаются как массивы байтов, а типы берутся как раз из type encoding. Естественно, передать неправильные аргументы там можно запросто.
Насчет возвращаемого значения, опять же, calling conventions все за нас сделают. Они на то и придуманы, чтобы все работало само собой, так сказать.
Возможно, это нужно, чтобы распарсить vararg-список у функции objc_msgSend?
Но зачем его парсить? objc_msgsend ничего с аргументами делать не должен — только найти реализацию метода и передать управление туда с сохранением состояния регистров и стека перед вызовом objc_msgsend. На уровне асма все вызовы методов превращаются в обычный вызов C функции со стандартным calling convention — несколько аргументов в регистрах, остальное в стеке. Опять же, с переопределением методов для jailbreak твиков можно много чего творить со списком аргументов. Обычное дело — заменить все аргументы на void* или id, если не знаешь их типов или вообще пофиг на них.
Я не очень понял, как передать управление с сохранением состояния стека до вызова, если не знаешь размер списка аргументов.
Ну как. На входе objc_msgsend в стек кладем все регистры, где обычно лежат аргументы. Дальше делаем свои дела, находим функцию. Восстанавливаем все регистры и возвращаем указатель стека на место, где он был на входе в objc_msgsend. Т.е. все регистры остаются как были, а стек указывает на то место, где лежат остальные аргументы. Вызываем наконец метод уже после эпилога objc_msgsend. Все выглядит так, будто не objc_msgsend вызвали, а просто напрямую метод класса. Просто перенаправляем вызов по нужному адресу.
Действительно, чудеса какие :) А это все ваши измышления или оно действительно так работает?
Это мои размышления на основе того, как работает вызов функций вообще — поэтому у меня и вопрос на счет того, зачем type encoding нужен рантайму, если на уровне асма все и без него по идее должно рабоать. Суть в том, чтобы после вызова вернуть все в прежнее состояние. Это и может сделать objc_msgsend с той лишь разницей, что после эпилога он сделает вызов найденного метода и получится, будто мы передали все эти аргументы прямо в метод, а не в objc_msgsend. Главное не трогать аргументы и стек, в котором могут лежать другие аргументы. Сделать это не так сложно — calling conventions действительно творят чудеса
Дело не совсем в этом. Подождите следующей статьи, я всё расскажу. К сожалению, эта статья изначально получилась слишком объемной, поэтому мне пришлось её укоротить и вынести некоторую информацию в следующую часть. В общем, цикл статей не заканчивается на этой.
Огромное спасибо за продолжение, жду следующих статей!
Некоторые мысли (я не имею практического знания ObjC, но тема очень интересная, какие-то мысли приходят в голову...)
У каждого объекта класса есть скрытое поле с именем isa, которое указывает на специальный объект, описывающий класс в рантайме. Там, в этом объекте хранится по сути таблица соответствия селекторов и функций. Это похоже на таблицу виртуальных функций? Было бы интересно сравнить. И еще интересно, как оно устроено в ObjectiveC++, где по идее должно как-то совмещаться?
Существуют ли штатные средства подключения и отключения методов к классам? (по идее это добавление и удаление записей из таблицы соответсивия селекторов функциям)
Можно ли «переключить» объект на другой «объект класса» (то есть переписать isa)?
Можно ли делать копии «объектов классов»?
Некоторые мысли (я не имею практического знания ObjC, но тема очень интересная, какие-то мысли приходят в голову...)
У каждого объекта класса есть скрытое поле с именем isa, которое указывает на специальный объект, описывающий класс в рантайме. Там, в этом объекте хранится по сути таблица соответствия селекторов и функций. Это похоже на таблицу виртуальных функций? Было бы интересно сравнить. И еще интересно, как оно устроено в ObjectiveC++, где по идее должно как-то совмещаться?
Существуют ли штатные средства подключения и отключения методов к классам? (по идее это добавление и удаление записей из таблицы соответсивия селекторов функциям)
Можно ли «переключить» объект на другой «объект класса» (то есть переписать isa)?
Можно ли делать копии «объектов классов»?
На эти и многие другие вопросы можно найти ответы здесь developer.apple.com/library/mac/documentation/Cocoa/Reference/ObjCRuntimeRef/index.html Рантайм умеет многое. Что касается objc++, то я не слышал, чтобы он чем-то отличался особенным. Это просто расширение для частичной поддержки C++. Основные проблемы конечно, когда мешаешь objc и C++, но так все очень прилично.
Нет, в Obj-C++ никакого совмещения нет, C++ объекты отдельно, Obj-C объекты отдельно.
Неплохо было бы сделать в начале статьи ссылку на первую часть однако.
>будет помещен в некую кеш-таблицу
Это называется inline caching, см. en.wikipedia.org/wiki/Inline_caching
И почитайте про устройство рантайма Smalltalk, многое будет намного понятнее. Можно почти сказать, что Obj-C это Smalltalk + C.
Уверен, тогда не будете считать «умниками» тех, кто говорит, что посылка сообщений — это посылка сообщений.
Это называется inline caching, см. en.wikipedia.org/wiki/Inline_caching
И почитайте про устройство рантайма Smalltalk, многое будет намного понятнее. Можно почти сказать, что Obj-C это Smalltalk + C.
Уверен, тогда не будете считать «умниками» тех, кто говорит, что посылка сообщений — это посылка сообщений.
Sign up to leave a comment.
Objective-C Runtime для Си-шников. Часть 2