Хотя я не очень знаком с инструментарием 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
, если нет веской причины поступить иначе.