Вопрос или проблема
Я пытаюсь прочитать документацию для инструкции ADRP arm64, и я не уверен в одном аспекте. Лучше всего это показать на коде:
ULONG64 uiAddr = 0xfffff80198964c08; //Адрес следующего операции
ULONG32 opcode = 0x900016d0; //Операция для инструкции ADRP, которую нужно разрешить
//Проверяем, правильная ли операция
if((opcode & 0x9F000000) != 0x90000000)
{
//Неверная операция
wprintf(L"Неверная операция для инструкции ADRP: 0x%X\n", opcode);
return -1;
}
ULONG64 imm;
imm = (opcode & 0x60000000) >> 29;
imm |= (opcode & 0x00FFFFE0) >> 3;
//Мне нужно это делать?
//uiAddr += sizeof(opcode); //Сдвинуть PC на размер операции
uiAddr += imm << 12;
uiAddr &= ~((0x1LL << 12) - 1);
ULONG uiReg = opcode & 0x1F;
wprintf(L"Разрешение адреса ADRP: x%u=0x%I64X\n", uiReg, uiAddr);
Так это работает – нужно ли мне сдвигать PC на размер операции?
.
Ответ или решение
Инструкция ADRP (Add Address of Page) в архитектуре ARM64 предназначена для вычисления адреса 4KB страницы и сохранения его в регистре. Давайте детально разберем приведенный вами код, чтобы понять, правильно ли вы реализовали разрешение адреса с использованием этой инструкции, и нужно ли двигать указатель программы (PC) на размер опкода.
Анализ кода
Ваша реализация начинается с проверки корректности опкода:
if((opcode & 0x9F000000) != 0x90000000)
{
//Bad opcode
wprintf(L"Bad opcode for ADRP instruction: 0x%X\n", opcode);
return -1;
}
Этот блок правильно проверяет, относится ли данное слово к инструкции ADRP. Далее вы извлекаете значение смещения (иммедиата):
ULONG64 imm;
imm = (opcode & 0x60000000) >> 29;
imm |= (opcode & 0x00FFFFE0) >> 3;
Здесь вы корректно выделяете значение смещения из опкода. Значение imm
будет содержать 21 бит, который нужно сместить на 12 бит влево, чтобы получить корректный адрес страницы.
Процесс разрешения адреса
Теперь давайте обратим внимание на переменную uiAddr
:
uiAddr += imm << 12;
uiAddr &= ~((0x1LL << 12) - 1);
Вы правильно добавляете смещение imm
к текущему адресу uiAddr
.
Вопрос о смещении указателя программы (PC)
Теперь, что касается вопроса о том, нужно ли увеличивать uiAddr
на размер опкода. В контексте архитектуры ARM64, указатель программы (PC) фактически указывает на адрес следующего исполняемого инструмента. Поэтому, для правильного расчета адреса, необходимо учитывать, что значение PC для текущей инструкции ADRP также может быть использовано в качестве базового адреса.
Однако, поскольку вы уже используете uiAddr
для хранения адреса текущей инструкции, не обязательно дополнительно увеличивать его на sizeof(opcode)
. Код будет корректным без этого действия, если uiAddr
инициализируется правильно.
Заключение
Таким образом, ваш код почти в полной мере описывает процесс разрешения адреса инструкции ADRP. Ваша реализация правильно обрабатывает опкод и вычисляет адрес, который потом можно использовать для работы с памятью. Необходимо отметить, что указатель программы (PC) фактически указывает на следующую инструкцию, и управление адресами выполняется с учетом этого. В данной реализации не требуется дополнительно смещать uiAddr
, так как это может вызвать некорректные обращения к памяти.
Применяя данные рекомендации, вы сможете более точно обрабатывать инструкции ADRP, что особенно актуально при работе с низкоуровневым кодом и системным программированием в архитектуре ARM64.