2011-08-02 3 views
4

По причинам, слишком сложным для объяснения здесь, мне нужно запустить x86 GCC-скомпилированную Linux-программу на платформе, которая является подмножеством x86. Эта платформа не имеет регистра% gs, , что означает, что она должна быть эмулирована, потому что GCC полагается на наличие регистра% gs.Подмножество x86 без регистра% gs: двоичный код исправления, который использует% gs вместо захвата для эмуляции?

В настоящее время у меня есть обертка, которая ловит исключения, когда программа пытается получить доступ к регистру% gs и эмулирует его. Но это собака медленно. Есть ли способ, чтобы я мог заранее скопировать коды опций в ELF с помощью эквивалентных инструкций, чтобы избежать ловушки и эмуляции?

ответ

3

(Это предполагает, что решение Адама Rosenfields не применит его, или подобный подход, вероятно, лучшим способ. решите его.)

Вы не указали, как вы эмулируете регистр% gs, но, вероятно, будет сложно заплатить за использование каждого, если у вас нет специальных знаний о программе, потому что в противном случае у вас всего 2 байта (в худшем, общем случае), который вы можете изменить с помощью патча. Конечно, если вы используете что-то вроде% es =% gs, оно должно быть относительно прямым.

Предполагая, что это может быть сделано для работы в вашем случае, стратегия заключается в сканировании исполняемых разделов ELF-файла и исправлении любой инструкции, которая использует или изменяет регистр GS. Это по крайней мере следующие инструкции:

  • Любая инструкция с префиксом замены сегмента GS (65 ожидать инструкций ветвления в этом случае префикс указывает на что-то другое)
  • push gs (0F A8)
  • pop gs (0F A9)
  • mov r/m16, gs (8C /r)
  • mov gs, r/m16 (8E /r)
  • mov gs, r/m64 (REX.W 8E /r) (Если вы поддерживаете 64 бит режима)

И любые другие инструкции, которые позволяют сегментные регистры (я не думаю, что в том, что гораздо больше, но я не 100%).

Все это происходит от Intel® 64 and IA-32 Architectures Software Developer's Manual Combined Volumes 2A and 2B: Instruction Set Reference, A-Z. Имейте в виду, что инструкции иногда префиксны с другими префиксами, иногда нет, поэтому вы, вероятно, должны использовать library, чтобы выполнять декодирование команд, а не слепо искать последовательности байтов.

Некоторые из приведенных выше инструкций должны быть относительно простыми, чтобы превратиться в call my_patch или аналогичные, но у вас, вероятно, возникнут проблемы с поиском того, что подходит в двух байтах и ​​работает в целом. int XX (CD XX) может быть хорошим кандидатом, если вы можете настроить вектор прерывания, но я не уверен, что он будет быстрее, чем метод, который вы сейчас используете.Разумеется, вам нужно будет записать, какая инструкция была исправлена, и обработчик прерывания (или что-то другое) реагирует по-разному в зависимости от обратного адреса (который получает ваш обработчик).

Вы можете быть в состоянии установить батут, если вы можете найти номер в пределах -128..127 байтов и использовать JMP rel8 (EB cb), чтобы перейти к батут (обычно другой JMP, но на этот раз с более места для целевого адреса), который затем обрабатывает эмуляцию команды и возвращается к инструкции после исправленного использования% gs.

Наконец-то я рекомендую держать код ловушки и эмуляции запущенным, чтобы поймать любые случаи, которые вы, возможно, не подумали (например, самомодифицируемый или введенный код). Таким образом, вы также можете регистрировать любые необработанные случаи и добавлять их в свое решение.

+0

Теперь мы перехватываем ошибки страниц, вызванные доступом к несуществующему регистру% gs, двухбайтовый метод прерывания быстрее, чем перехват ошибки страницы? –

+0

@Phillip: Поскольку я не знаю вашу среду исполнения, я не знаю, можно ли даже установить обработчик прерываний, и, как я писал, это, вероятно, не будет намного быстрее (вам нужно будет самому это время) , Я упомянул только об использовании прерываний, потому что это двухбайтная инструкция и позволяет «прыгать вперёд». Я бы предложил использовать 'int3' (' CC'), который вызывает 'SIGTRAP', но это будет мешать отладке. – user786653

4

Вы пробовали компилировать свой код с помощью опции -mno-tls-direct-seg-refs? С моей страницы НКИ человека (i686-яблоко-darwin10-GCC-4.2.1):

-mtls-direct-seg-refs 
    -mno-tls-direct-seg-refs 
     Controls whether TLS variables may be accessed with offsets from 
     the TLS segment register (%gs for 32-bit, %fs for 64-bit), or 
     whether the thread base pointer must be added. Whether or not this 
     is legal depends on the operating system, and whether it maps the 
     segment to cover the entire TLS area. 

     For systems that use GNU libc, the default is on. 
+0

Я думал, что это FS для 32-битных и GS для 64-битных? – Mehrdad

+0

@Merhdad: Я думаю, что это зависит от ОС. В Mac OS X версии 10.6 оба 32- и 64-разрядных исполняемых файла, похоже, используют GS в тесте, который я только что сделал; Linux 2.6.32 также использует GS для 64-разрядной версии. –

+0

Я говорил о Windows на самом деле, извините (см. [Здесь] (http://en.wikipedia.org/wiki/X86-64#Windows)). Не знаю о других. – Mehrdad

Смежные вопросы