Может ли программный счетчик на процессорах Intel считываться напрямую (без «трюков») в режиме ядра или в каком-либо другом режиме?Прямой счетчик программ для чтения
ответ
Нет, доступ к EIP/IP невозможен напрямую, но в коде, зависящем от положения, это постоянная времени связи, поэтому вы можете использовать ближайший (или удаленный) символ как немедленный.
Чтобы получить EIP или IP в позиционно-независимом коде:
call _here
_here: pop eax
; eax now holds the PC.
Но это дисбалансы на вызов/обратный стек предсказателя, поэтому предпочитает вызов функции, которая на самом деле вернуться, чтобы избежать ветвлений mispredicts на 15 или так будущих ret
инструкций в ваших родительских функциях. (Если вы не не собирается возвращаться, или так редко, что это не имеет значения.)
get_retaddr:
mov eax, [esp]
ret ; keeps the return-address predictor stack balanced
В режиме x86-64, RIP можно считывать непосредственно с помощью RIP-относительная lea
.
default rel ; NASM directive: use RIP-relative by default
lea rax, [_here] ; RIP + 0
_here:
MASM: lea rax, [rip]
AT & T синтаксис: lea 0(%rip), %rax
Если вам нужен адрес конкретного обучения, как правило, что-то вроде этого делает трюк:
thisone:
mov (e)ax,thisone
(Примечание. На некоторых ассемблерах это может сделать неправильное дело и прочитать слово из [thisone], но обычно есть некоторый синтаксис f или получение ассемблера для правильной работы.)
Если ваш код статически загружен на определенный адрес, ассемблер уже знает (если вы сказали ему правильный начальный адрес) абсолютные адреса всех инструкций. Динамически загруженный код, скажем, как часть приложения на любой современной ОС, получит правильный адрес благодаря перемещению адреса, выполняемому динамическим компоновщиком (при условии, что ассемблер достаточно умен, чтобы генерировать таблицы перемещения, которые они обычно представляют).
Спасибо за информацию, действительно хорошая идея:) –
Я пробовал это на x86-64 с встроенной сборкой gcc, но получил «ошибку в backend: 32-разрядная абсолютная адресация не поддерживается в 64-битном режиме» с использованием llvm 6.1.0. Является ли эта проблема LLVM или не возможна в 64-битном режиме? – csl
@csl: либо вы находитесь на OS X (где нет обходного пути, кроме использования 'lea rax, [thisone]'), или вы используете Linux для создания общего объекта, и, следовательно, это тоже не сработает. ('mov'-instant требует постоянный адрес времени ссылки, поэтому он работает только в зависимом от положения коду.Но если вы создаете исполняемый файл Linux, [ваш компилятор может по умолчанию сделать независимый от позиции исполняемый файл, а '-no-pie -fno-pie' делает исполняемый файл, зависящий от положения, где вы можете использовать абсолютную адресацию] (https: //stackoverflow.com/questions/43367427/32-bit-absolute-addresses-no-longer-allowed-in-x86-64-linux). –
Нет инструкции для прямого считывания указателя инструкции (EIP) на x86. Вы можете получить адрес текущей команды быть собран с небольшим количеством встроенного ассемблера:
// GCC inline assembler; for MSVC, syntax is different
uint32_t eip;
__asm__ __volatile__("movl $., %0", : "=r"(eip));
директива .
ассемблер заменяется на адрес текущей инструкции по ассемблеру. Обратите внимание, что если вы завернете вышеприведенный фрагмент в вызове функции, вы получите только тот же адрес (внутри этой функции). Если вы хотите получить более полезную функцию C, вы можете вместо этого использовать некоторые не-ассемблерный:
// In a C header file:
uint32_t get_eip(void);
// In a separate assembly (.S) file:
.globl _get_eip
_get_eip:
mov 0(%esp), %eax
ret
Это означает, что каждый раз, когда вы хотите получить указатель команд, это немного менее эффективно, так как вам нужно вызов дополнительных функций. Обратите внимание, что выполнение этого способа не удаляет стек обратного адреса (RAS). Столбец обратного адреса представляет собой отдельный стек обратных адресов, используемый внутренним процессором для облегчения branch target prediction для инструкций RET.
Каждый раз, когда у вас есть инструкция CALL, текущий EIP попадает в RAS, и каждый раз, когда у вас есть команда RET, RAS выставляется, а верхнее значение используется как предсказание для ветвления для этой команды.Если вы испортите RAS (например, не сопоставляя каждый CALL с RET, как в Cody's solution), вы получите целую кучу ненужных неверных предсказаний филиала, замедляющих вашу программу. Этот метод не удаляет RAS, так как он имеет пару команд CALL и RET.
Спасибо, вы, ребята, рок :) –
Большое спасибо за информацию, я не знал, что было два стека .. :) –
RAS - это внутренний стек, используемый процессором; он никак не доступен для кода. Он используется только для предсказания целевой ветви. Без него код все равно будет функционировать правильно, только медленнее. –
На x86-64 вы можете сделать, например:
lea rax,[rip] (48 8d 05 00 00 00 00)
Спасибо! В чем смысл чисел? –
thats кодировка команды - theres неявное 32-битное смещение, которое равно 0, я не уверен, есть ли более короткая кодировка – matja
'lea rax, [rip]' не работает в NASM 2.10. Кажется, что RIP может использоваться косвенно только с 'rel', как в' lea rax, [rel _start] '? –
Вы также можете прочитать из/Proc/стат. Проверьте файлы proc.
Можете ли вы указать, где? Я не мог найти это легко. –
В/proc/stat вы можете найти указатель на инструкцию (EIP) –
Я думаю, вы имеете в виду '/ proc/self/stat', было бы здорово цитировать manpage. –
Существует архитектуру, независимый (но НКА зависимый) способ доступа адреса, который в настоящее время выполняется с использованием меток в качестве значений:
http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html
void foo()
{
void *current_address = $$current_address_label;
current_address_label:
....
}
Это не совсем сборка :-) – hirschhornsalz
это должно быть '&& current_address_label', а не' $$ ' –
Разве это не относительный адрес (а не IP)? –
- 1. Счетчик программ?
- 2. Счетчик программ, не продвигающийся
- 3. Сборка филиала: счетчик программ
- 4. C для 16f628, счетчик программ идет haywire
- 5. Счетчик программ Verilog с ветвлением
- 6. Счетчик программ в ARM-сборке
- 7. Изменить счетчик программ в C
- 8. Scala: проблема с прямой ссылкой + счетчик циклов
- 9. Программа для чтения программ через общие папки
- 10. Скрытое оглавление для программ чтения с экрана
- 11. Порядок чтения таблицы HTML для программ чтения с экрана
- 12. Можно ли читать счетчик программ другой нити?
- 13. Значение ПК между двумя инструкциями (счетчик программ)
- 14. Перемещение рамки/счетчик программ/переполнение массива
- 15. Изменить счетчик программ (ПК) на сохраненный адрес
- 16. Счетчик программ VHDL, ошибка нескольких постоянных драйверов
- 17. Как работает счетчик программ в 8085 году?
- 18. Прямой ByteBuffer относительный против абсолютной производительности чтения
- 19. Pywin32 Каталог чтения служебных программ Windows
- 20. Недопустимый указатель в файле чтения программ C
- 21. JS сгенерированный код, читаемый для программ чтения с экрана
- 22. Рекомендации для программ с петлями
- 23. Что означает «каждый поток JVM имеет свой собственный счетчик программ»?
- 24. Dynamodb: удаляет счетчик чтения или записи?
- 25. Python openpyxl: режим только для чтения возвращает другой счетчик строк
- 26. GUI Специальный счетчик писем Java для чтения в файле
- 27. Счетчик подписчиков Feedburner и приложение для чтения RSS-сообщений
- 28. Регистрация списка программ Windows для установленных программ
- 29. iOS выбор программ из программ для фотографий
- 30. Что такое счетчик программ потоков с точками останова?
Ах, я люблю этот трюк. В ARM возникают проблемы с конвейерной обработкой при чтении ПК. Эта проблема присутствует и в процессорах Intel? – strager
Нет, его нет на x86. (Btw - проблема конвейерной обработки ARM сумасшедшая) –
В x86 у вас есть стоимость ветки, что намного хуже для конвейера, чем просто чтение ПК. PIC на ARM намного дешевле, чем x86, даже с странностями трубопровода. –