Как вы создаете таблицы переходов в x86 / x64? - PullRequest
0 голосов
/ 13 октября 2019

В настоящее время я изучаю x86 / x64 asm, и я хотел попытаться составить таблицу переходов, но я не могу понять, что я делаю неправильно.

Сама концепция не нова дляЯ просто не могу понять, почему это не работает. Я видел использование [] несколько раз, когда я исследовал это, но я не уверен, что это правильный способ сделать это.

.data
var qword 10

.code
main proc

    mov rax, var
    jmp [table]
back:
    ret

table:
qword subroutine, subroutine2

subroutine:

    mul var
    jmp back

subroutine2:

    mul var
    jmp back

main endp
end

Когда я прохожу код ион пропускает инструкцию jmp и при ret выдает access violation reading location 0x00000000 error

1 Ответ

2 голосов
/ 14 октября 2019

Обратите внимание, что, как прокомментировано, MASM игнорирует []. Вместо этого MASM идет по типу метки. В этом случае проблема заключается в том, что: after table (table :) создает метку типа «код», которая обычно используется в качестве цели перехода или вызова, поэтому jmp [таблица] или таблица jmp переходят в таблицу так, как если бы она былаcode.

Удаление: и помещение qword (или dq можно использовать) в одну строку, изменение таблицы на тип qword, поэтому jmp [table] или jmp table загружает адрес qword из таблицы в RIPи выполняет ветвление как требуется.

table   qword   subroutine, subroutine2

Однако, если вы хотите проиндексировать таблицу, вам нужно будет либо использовать регистр для хранения смещения таблицы (например, lea r9, table),или в случае Visual Studio перейдите в проект / свойства / компоновщик / система / включить большие адреса: нет (устанавливает параметр компоновщика / LARGEADDRESSAWARE: NO). Ниже я разместил примеры для обоих случаев.


Этот пример работает с ML64.EXE (MASM) из Visual Studio. Таблица может быть в разделе кода или данных. Если таблица является первой строкой в ​​данных, lea генерирует {4C 8D 0D 79 E5 00 00}, если таблица является первой строкой в ​​коде, lea генерирует {4C 8D 0D E1 FF FF FF}. Я не знаю, что лучше для производительности. Казалось бы, если кэш данных используется не полностью, то он будет хранить копию таблицы кеша данных.

        .data
tbl     dq      fun1, fun2, fun3            ;table
        .code

main    proc
        lea     r9,tbl
        mov     rax,0
main0:  jmp     qword ptr [r9+rax*8]
main1:: inc     rax
        cmp     rax,3
        jb      main0
        xor     eax,eax
        ret
main    endp

fun1    proc
        mov     rdx,1
        jmp     main1
fun1    endp

fun2    proc
        mov     rdx,2
        jmp     main1
fun2    endp

fun3    proc
        mov     rdx,3
        jmp     main1
fun3    endp

        end

С параметром компоновщика Visual Studio / LARGEADDRESSAWARE: НЕТ, тамнет необходимости использовать второй регистр. Таблица может быть в разделе данных или кода. Если таблица является первой строкой в ​​данных, jmp генерирует {FF 24 C5 00 00 3D 00}, если таблица является первой строкой в ​​коде, jmp генерирует {FF 24 C5 80 1A 2D 01}. Я не знаю, что лучше для производительности. Казалось бы, если кэш данных используется не полностью, то он будет хранить копию таблицы кеша данных.

        .data
tbl     dq      fun1, fun2, fun3            ;table
        .code
main    proc
        mov     rax,0
main0:  jmp     qword ptr [tbl+rax*8]
main1:: inc     rax
        cmp     rax,3
        jb      main0
        xor     eax,eax
        ret
main    endp

fun1    proc
        mov     rdx,1
        jmp     main1
fun1    endp

fun2    proc
        mov     rdx,2
        jmp     main1
fun2    endp

fun3    proc
        mov     rdx,3
        jmp     main1
fun3    endp
...