среда, 1 мая 2013 г.

ObjC messages to nil

It's wide known fact that in ObjC you can safely send any message to 'nil' object. Implementation turned out to be a bit more tricky than I supposed, here is code of 'libobjc': Message will go to another receiver if system finds some value in '__objc_nilReceiver'! Moreover I found private ad-hoc function to change value of this variable without a hassle. And here is code that prints "Some" Just interesting fact to know...

суббота, 23 февраля 2013 г.

How to compile 'otool'

As a personal note.

1. Get it here: http://www.opensource.apple.com/source/cctools
2. Modify 'libstuff' Makefile to avoid 'LTO'(link time optimization) support. '-DLTO...' and 'lto.o'
3. Run 'make' inside libstuff directory
4. Run 'make' inside otool directory (don't remember exactly, may be Makefile update required as well)

otool.NEW

Error I was getting:
../lto.c:8:10: fatal error: 'llvm-c/lto.h' file not found
#include <llvm-c/lto.h>

среда, 30 января 2013 г.

Avoiding "-load-all" linker flag

Found a nice solution on how to avoid "-load-all" linker flag.
https://github.com/square/KIF/blob/master/Additions/LoadableCategory.h
Just quoting here:
//
// LoadableCategory.h
// KIF
//
// Created by Karl Stenerud on 7/16/11.
// Licensed to Square, Inc. under one or more contributor license agreements.
// See the LICENSE file distributed with this work for the terms under
// which Square, Inc. licenses this file to you.
/** Make all categories in the current file loadable without using -load-all.
*
* Normally, compilers will skip linking files that contain only categories.
* Adding a call to this macro adds a dummy class, which causes the linker
* to add the file.
*
* @param UNIQUE_NAME A globally unique name.
*/

#define MAKE_CATEGORIES_LOADABLE(UNIQUE_NAME) @interface FORCELOAD_##UNIQUE_NAME @end @implementation FORCELOAD_##UNIQUE_NAME @end

воскресенье, 25 ноября 2012 г.

Правильно считаем смещение функции в Mach-O binary

Несколько более грамотный подход. Допустим удалось определить, что искомая функция начинается по адресу 0x000A36E0 (речь об i386), - самое время рассматривать Mach-O Header


Запоминаем - Fat binary, контент i386 части начинается со смещения 0x129000
Loading command на __TEXT,__text сегмент, секцию


File offset - 0x1880
Address offset - 0x2880

Итак:

i386 __TEXT,__text file offset start: 0x129000 + 0x1880 = 0x12A880
Function address offset from section start: 0xA36E0 - 0x2880 = 0xA0E60

Function file offset from start: 0x12A880+0xA0E60 = 0x1CB6E0

P.S. Все адреса и смещения вымышлены, любое совпадение с реальными - случайно (на самом деле нет)

воскресенье, 15 апреля 2012 г.

Кто меня звал ?

Наверное одна из наиболее часто используемых команд при отладке с использованием GDB это bt/backtrace/where. Этой командой можно раскрутить стек и увидеть каким образом мы пришли к текущему этапу выполнения. Достаточно знать несколько деталей работы со стеком, чтобы получить ту же самую информацию во время работы приложения.

Вызов метода в Objective-C сводится к выполнению Си функции objc_msgSend или нескольких ее вариаций. Сама функция после определения кода который нужно выполнить делает переход к нему, оставляя неизменным стек, т.о. и в выводе GDB не видно objc_msgSend.

Выполнение каждой функции начинается с помещения в стек указателя на стек фрейм предыдущей функции и сохранении фрейма стека текущей:

    push   %ebp 
    mov    %esp,%ebp

Указатель на stack frame хранится в регистре %ebp.

Стек растет от старших адресов к младшим, следующим образом он будет выглядеть при вызове метода -[SomeObject setObj:(NSObject*)arg1]

+------------------------+                |
|    (NSObject*)arg1     |                |
+------------------------+                |
|  указатель на строку   |               \|/
|  selector, "setObj:"   |                '
+------------------------+
|      SomeObject*       |                
+------------------------+
|  %eip, адрес возврата  |
+------------------------+
| %ebp, last stack frame | <- "push %ebp", в начале функции
+------------------------+ ..
                           '`- "mov %esp,%ebp", %ebp указывает сюда

Таким образом в %ebp при выполнении текущей функции лежит адрес на стеке, где лежит значение %ebp от предыдущей выплоняемой функции из которой был произведен вызов текущей. Воспользовавшись знаниями выше, можно получить следующую функцию:

static id getSender()
{
  id result = nil;
  __asm(  "push %%ebx\n"
  "push %%ebp\n"
  "mov (%%ebp),%%ebx\n"
  "mov %%ebx,%%ebp\n"
  "mov (%%ebp),%%ebx\n"
  "mov %%ebx,%%ebp\n"
  "mov 8(%%ebp),%%ebx\n"
  "mov %%ebx,%0\n"
  "pop %%ebp\n"
  "pop %%ebx"
  :"=r"(result)
  );
  return result;
}
 Вызов данной функции вернет объект из которого был произведен вызов текущего метода, а с небольшой модификацией можно получить и метод из которого был произведен вызов.