Pull to refresh

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)?
Можно ли делать копии «объектов классов»?
На эти и многие другие вопросы можно найти ответы здесь developer.apple.com/library/mac/documentation/Cocoa/Reference/ObjCRuntimeRef/index.html Рантайм умеет многое. Что касается objc++, то я не слышал, чтобы он чем-то отличался особенным. Это просто расширение для частичной поддержки C++. Основные проблемы конечно, когда мешаешь objc и C++, но так все очень прилично.
Нет, в Obj-C++ никакого совмещения нет, C++ объекты отдельно, Obj-C объекты отдельно.
Отнаследовать класс сразу от NSObject и от C++ класса с виртуальными функциями нельзя?
Нет, объектные системы плюсов и Obj-C разделены.
Неплохо было бы сделать в начале статьи ссылку на первую часть однако.
>будет помещен в некую кеш-таблицу
Это называется inline caching, см. en.wikipedia.org/wiki/Inline_caching

И почитайте про устройство рантайма Smalltalk, многое будет намного понятнее. Можно почти сказать, что Obj-C это Smalltalk + C.
Уверен, тогда не будете считать «умниками» тех, кто говорит, что посылка сообщений — это посылка сообщений.
Sign up to leave a comment.

Articles