и посмотреть медиа
S0ER - архитектура и кодинг
и посмотреть медиа
Материалы по архитектуре ПО, программированию и карьерному росту в IT.
Материалы по архитектуре ПО, программированию и карьерному росту в IT.
S0ER фокусируется на архитектуре программного обеспечения, программировании и профессиональном развитии. Канал предлагает глубокие разборы, примеры кода и стратегии для продвижения в IT-сфере.
Низкий уровень: как выглядят вызовы функций по указателю на ASM В языках высокого уровня, таких как C или C++, часто используются указатели на функции. Это позволяет динамически выбирать, какую функцию вызвать в runtime. Но как это выглядит на уровне ассемблера? Давайте разберемся. Для начала рассмотрим простой пример на C, где используется указатель на функцию: int callme() { return 1; } void main() { int (*func_ptr)() = callme; func_ptr(); } Здесь мы создаем указатель на функцию func_ptr, который указывает на функцию callme, и затем вызываем функцию через этот указатель. Как это выглядит в ассемблере? Используем Compiler Explorer, чтобы преобразовать этот код в ассемблер. Вот что получилось: callme: push rbp mov rbp, rsp mov eax, 1 pop rbp ret main: push rbp mov rbp, rsp sub rsp, 16 mov QWORD PTR [rbp-8], OFFSET FLAT:callme mov rax, QWORD PTR [rbp-8] call rax nop leave ret Что здесь происходит? Создание указателя на функцию: В функции main мы видим, что адрес функции callme сохраняется в памяти по адресу [rbp-8]: mov QWORD PTR [rbp-8], OFFSET FLAT:callme Здесь OFFSET FLAT:callme — это адрес функции callme в памяти. Загрузка указателя в регистр: Затем этот адрес загружается в регистр rax: mov rax, QWORD PTR [rbp-8] Вызов функции по указателю: После этого происходит вызов функции через регистр rax: call rax Инструкция call использует значение в регистре rax как адрес функции, на которую нужно перейти. Пролог и эпилог Как и в случае с обычным вызовом функции, здесь также присутствуют пролог и эпилог: Пролог: push rbp mov rbp, rsp sub rsp, 16 Здесь сохраняется значение rbp, устанавливается новый кадр стека и выделяется место для локальных переменных. Эпилог: leave ret Здесь восстанавливается значение rbp и выполняется возврат из функции. Пример с массивом в функции Давайте добавим массив в функцию callme и посмотрим, как это повлияет на ассемблерный код: int callme() { char a[128]; return 1; } В ассемблере это будет выглядеть так: callme: push rbp mov rbp, rsp sub rsp, 8 ;
Открыть канал и посмотреть медиаТолько зарегистрированные пользователи могут делиться своим мнением.
Станьте первым, кто поделится своим впечатлением об этом ресурсе!