Как мне написать простую встроенную инструкцию asm от C на Linux 64 бит? - PullRequest
4 голосов
/ 27 июля 2010

Я пишу простую программу на c, и мое требование - напечатать RIP (указатель инструкций) из какой-то функции программы.я не хочу использовать ptrace.

единственное, что я попробовал с встроенным asm: asm ("movl %% rip,% 0;": "= r" (val)) это должно скопировать мое значение регистра rip в переменную val, но я получаю ошибку компиляции.

, если я использую ebp / esp, которые являются базовыми указателями и указателями стека для 32-битной машины, я не получаю никакой ошибки компиляции и мойУ val есть шестнадцатеричное число.

У меня есть несколько вопросов:

1), поскольку моя машина 63-битная, как вышеприведенная инструкция могла читать 32-битные регистры?

2) почему я не могу прочитать ни один регистр для 64 бит, есть ли проблема b'caz 'r' ?

3), когда я использую eip, который предназначен для 32Если я получаю ошибку компиляции, значит ли это, что регистры IP ограничены для чтения?

Ответы [ 2 ]

9 голосов
/ 27 июля 2010
  1. Ваша машина 64 бит, а не 63 бит =).Вы смогли прочитать 32-битные регистры, потому что вы компилируете и запускаете свою программу как 32-битный исполняемый файл [1].
  2. Вы не можете прочитать 64-битные регистры, потому что вы компилируете изапуск вашей программы в виде 32-битного исполняемого файла.Да, у вас есть 64-битный процессор, но он по-прежнему может запускать 32-битные исполняемые файлы (если ваша ОС поддерживает его, что, безусловно, ваша), и, очевидно, ваша цепочка инструментов компилятора строит 32-битные по умолчанию.Если вы используете gcc, попробуйте использовать флаг -m64 или прочитайте документацию компилятора для получения дополнительной информации.
  3. В отличие от rip, регистр eip не может быть доступен напрямую.Вы можете получить значение eip способом, описанным Джимом в его ответе.

[1] вы сможете прочитать 32-битные регистры из64-битный исполняемый файл в любом случае;32-разрядные регистры по-прежнему доступны в 64-разрядном режиме, так же как вы можете получить доступ к 16-разрядным регистрам в 32-разрядном режиме.


В вашем примере все еще есть несколько проблем:

Во-первых, хотя rip доступен в 64-битном режиме, он доступен как режим адресации;это не нормальный регистр.Если вы хотите загрузить его значение, вам нужно использовать LEA, а не MOV.

Second, поскольку rip является 64-битным регистром, вам нужно использовать суффикс q дляваши инструкции вместо l.Вот пример программы с этими двумя проблемами:

#include <stdio.h>
#include <inttypes.h>

int main(int argc, char *argv[]) {
    uint64_t ip;
    asm("leaq (%%rip), %0;": "=r"(ip));
    printf("rip is 0x%016" PRIx64 "\n", ip);
    return 0;
}

, которая, кажется, прекрасно работает на моей машине.

5 голосов
/ 27 июля 2010

Вы можете получить значение регистра EIP, выполнив:

    call a  ; this pushes the value of EIP onto the stack
a:          
    pop ebx ; pops the value of EIP into register ebx

, а затем вы можете просто прочитать ebx.

...