x64 Ассемблер jmp с использованием таблицы смещений - PullRequest
0 голосов
/ 10 октября 2018

Для эффективности я хочу использовать таблицу адресов, которую я могу индексировать регистром в jmp в подпрограмме ассемблера.

Пример может сделать это более понятным ...

.CODE   
...
AppendByte  PROC
    XOR     RAX, RAX
    MOV     AL,  CL     ; Get this 0-7 index from somewhere else
    JMP     QWORD PTR[RAX + OFFSET APPENDBYTETABLE]
AppendByte  ENDP

AppendByte_7:
    ; Do stuff...
    RET

AppendByte_6:
    ; Do stuff...
    RET

...
AppendByte_0:
    RET

.DATA
    APPENDBYTETABLE QWORD   AppendByte_0, AppendByte_1, AppendByte_2,
                            AppendByte_3, AppendByte_4, AppendByte_5,
                            AppendByte_6, AppendByte_7

END 

Это компилируется в VS2017, но затем я получаю ошибку компоновщика.Я думаю, что это связано с использованием адресов FAR.Как мне сгенерировать NEAR-смещения и выполнить SHORT jmp для смещений, хранящихся в таблице в сегменте DATA?

Обратите внимание, что если я добавлю метки AppendByte_x внутри моего proc, то компилятор квакает.

ПОСТАНОВИЛИ!РЕДАКТИРОВАТЬ после консультации с Fuz ...

XOR         RAX, RAX
MOV         AL, REG_PREFIXCODEBITS  
LEA         RCX, APPENDBYTETABLE
JMP         QWORD PTR [RCX + RAX * 8]

1 Ответ

0 голосов
/ 10 октября 2018

Хотя я не очень знаком с инструментарием Microsoft, я считаю, что основная проблема заключается в том, что в режимах адресации SIB (масштаб / индекс / база), таких как [RAX + OFFSET APPENDBYTETABLE], смещение ограничено одним или четырьмя байтами.Компоновщик Microsoft хочет, чтобы ваша программа загружалась с любого адреса, включая адреса выше первого 4 ГБ адресного пространства, требуя, чтобы полные 8 байтов представляли адрес.Очевидно, что 4 байта недостаточно для размещения 8 байтов, поэтому компоновщик справедливо жалуется.

Чтобы это исправить, сначала нужно загрузить регистр с адресом APPENDBYTETABLE, а затем индексировать в таблицу.Общий способ сделать это - использовать инструкцию lea (эффективный адрес загрузки).lea rax, foo похоже на mov rax, foo, но вместо загрузки памяти в foo возвращается адрес foo.Это можно использовать в сочетании с режимом относительной адресации rip (указатель инструкции) для получения адреса APPENDBYTETABLE, несмотря на то, что смещение снова ограничено 4 байтами.Это связано с тем, что компоновщик предполагает, что каждая программа или DLL по отдельности меньше 2 ГБ, поэтому 32-разрядного смещения со знаком всегда достаточно, чтобы найти адрес переменной или функции относительно местоположения текущей инструкции.Ассемблер неявно выбирает режим относительной адресации rip, когда вы обращаетесь к переменной напрямую, без использования регистра индекса или режима адресации SIB:

lea rax, APPENDBYTETABLE   ; load address of APPENDBYTETABLE rip-relative

Конечно, вы также можете использовать mov reg, offset foo для загрузки адресаfoo.При этом используется форма mov с немедленным 8-байтовым.Однако эта инструкция имеет более длинную кодировку, чем lea reg, foo, она, вероятно, медленнее и, возможно, требует от загрузчика исправления правильного адреса во время выполнения, что замедляет запуск вашей программы.Просто придерживайтесь lea, если нет веской причины поступить иначе.

...