Сборка некоторого кода вне строки с помощью макросов nasm - PullRequest
0 голосов
/ 25 мая 2018

Рассмотрим макрос nasm, который используется для вставки некоторой сборки при каждом вызове, в этом случае для проверки, равен ли переданный аргумент 42:

%macro special_handler_if_42 1
    cmp  42, %1
    jne  %%skip
    ; some additional assembly to handle the %1 == 42 case
    push %1
    push 42
    call some_func
%%skip:
%endmacro

В случае, если равно мы выполняем какое-то дополнительное действие, в противном случае мы просто продолжаем с кодом, следующим за макросом.Пока все хорошо.

Теперь я хочу написать макрос функционально идентичным образом, за исключением того, что регистр «равно 42», который бывает очень редким, перемещен «вне строки»,так что случай сброса (без перехода) является случаем по умолчанию, что-то вроде (не показано в виде макроса сейчас):

    cmp  42, rax
    je  equals_42
jump_back:
    ; the rest of the code that follows the macro
    ret

    ; somewhere outside the current function
equals_42:
    push rax
    push 42
    call some_func
    jmp jump_back

Это будет более эффективным во время выполнения и потенциально может сохранитьпространство кеша.Я не уверен, как написать макрос с нелокальным эффектом, как это.Идеи приветствуются.

1 Ответ

0 голосов
/ 26 мая 2018

Если вы не возражаете разделить макрос на два макроса, один из которых выполняет тест, а другой обрабатывает утверждение, тогда вы можете использовать стек контекста NASM .

Я вообразил систему макросов вида assert_XXX, которые очень похожи и выполняют определенные тесты.
Один assertions_handler после завершения функции генерирует любой необходимый обработчик.

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

assert_XXX также определит контекстные локальные макросы argX для передачи своего аргумента обработчику, поэтому нет необходимости что-либо жестко кодировать.

BITS 64

%macro assert_not_equal 2
    ;Create and push a new context (The name is optional but goodpractice)
    %push assert_equal_ctx

    %define %$arg1 %1
    %define %$arg2 %2

    cmp  %1, %2
    je  %$handler

%$jump_back:

%endmacro


%macro assert_greater 2
    %push assert_greater_ctx

    %define %$arg1 %1
    %define %$arg2 %2

    cmp  %1, %2
    jbe  %$handler

%$jump_back:

%endmacro

%macro assertions_handler 0

    %rep 1000

        %ifctx assert_equal_ctx

        %$handler:
            push %$arg1
            push %$arg2
            call somefunc
            jmp %$jump_back

            %pop assert_equal_ctx

        %elifctx assert_greater_ctx

        %$handler:
            push %$arg1
            push %$arg2
            call somefunc2

            %pop assert_greater_ctx

        %else

            %exitrep

        %endif
    %endrep
%endmacro


;
;TEST TEST TEST TEST TEST TEST TEST TEST
; 


assert_not_equal rax, 5

nop
nop
nop

assert_greater rax, 8

nop
nop
nop

ret

assertions_handler

;
; Handler functions
;

somefunc:
    ret

somefunc2:
    ret

Максимальное количество утверждений для каждой функции установлено равным 1000, вы можете увеличить его до 2 62 .

...