Требуется разъяснение адресации памяти MIPS в lw

Я пытаюсь понять приложение MIPS, но меня немного смущают следующие инструкции:

la      $k1, off_9FC005A8
lw      $k1, (off_9FC005D4 - 0x9FC005A8)($k1)
jr      $k1

В моем понимании это будет равнозначно следующему псевдокоду C:

$k1 = *off_9FC005A8;
$k1 = *($k1 + (*off_9FC005D4 - 0x9FC005A8));

Итак, зная следующее:

off_9FC005A8:   .word 0x9FC01508
off_9FC005D4:   .word 0x9FC011B4

Вы получите:

$k1 = 0x9FC01508;
$k1 = *($k1 + (0x9FC011B4 - 0x9FC005A8));

Остается: $k1 = 0x9FC02114. Однако это смещение находится на полпути к блоку кода, который я уже просмотрел и подтвердил правильность. Значит, мое понимание этих инструкций и адресации памяти ошибочно?


person PeterBelm    schedule 24.11.2010    source источник


Ответы (1)


Это переводится в этот код:

$k1 = &off_9FC005A8;                         // we load an address here! 
$k1 = *($k1 + (&off_9FC005D4 - &0x9FC005A8)); // we do a memory access here

k1 сначала загружается с адресом, указывающим на начало таблицы констант. Это то, что делает псевдоинструкция la. Это переводится как «адрес загрузки».

Затем выполняется доступ к памяти, который берет только что загруженный адрес в качестве базы и использует разницу между двумя записями в качестве смещения.

Это простая адресация в массив.

person Nils Pipenbrinck    schedule 24.11.2010
comment
Хорошо, но разве это не оставит меня с $k1, содержащим 0x9FC02114? Что не кажется подходящим местом для перехода. - person PeterBelm; 24.11.2010
comment
Теперь я понимаю, что все сводится к глупому способу, которым IDA выводит сборку, пытаясь быть умным, но если вы не узнаете поведение, это довольно запутывает. Фактическая инструкция: lw $k1, 0x2C($k1) - person PeterBelm; 24.11.2010