Понимание макроса NASM

Я нашел этот макрос в исходном файле сборки и просто не могу понять, как он работает.

Итак, сначала я обхожу эту функцию (hevc_deblock.h ):

cglobal hevc_v_loop_filter_chroma_8, 3, 5, 7, pix, stride, tc, pix0, r3stride
    sub            pixq, 2
    lea       r3strideq, [3*strideq]
    mov           pix0q, pixq
    add            pixq, r3strideq
    TRANSPOSE4x8B_LOAD  PASS8ROWS(pix0q, pixq, strideq, r3strideq)
    CHROMA_DEBLOCK_BODY 8
    TRANSPOSE8x4B_STORE PASS8ROWS(pix0q, pixq, strideq, r3strideq)
    RET

Итак, я предполагаю, что cglobal, похоже, искажает имена, поэтому я ищу его в других включенных файлах, я нахожу этот макрос внутри макроса cglobal (x86util.asm):

%macro CAT_UNDEF 2
    %undef %1%2
%endmacro

%macro DEFINE_ARGS 0-*
    %ifdef n_arg_names
        %assign %%i 0
        %rep n_arg_names
            CAT_UNDEF arg_name %+ %%i, q
            CAT_UNDEF arg_name %+ %%i, d
            CAT_UNDEF arg_name %+ %%i, w
            CAT_UNDEF arg_name %+ %%i, h
            CAT_UNDEF arg_name %+ %%i, b
            CAT_UNDEF arg_name %+ %%i, m
            CAT_UNDEF arg_name %+ %%i, mp
            CAT_UNDEF arg_name, %%i
            %assign %%i %%i+1
        %endrep
    %endif

    %xdefine %%stack_offset stack_offset
    %undef stack_offset ; so that the current value of stack_offset doesn't get baked in by xdefine
    %assign %%i 0
    %rep %0
        %xdefine %1q r %+ %%i %+ q
        %xdefine %1d r %+ %%i %+ d
        %xdefine %1w r %+ %%i %+ w
        %xdefine %1h r %+ %%i %+ h
        %xdefine %1b r %+ %%i %+ b
        %xdefine %1m r %+ %%i %+ m
        %xdefine %1mp r %+ %%i %+ mp
        CAT_XDEFINE arg_name, %%i, %1
        %assign %%i %%i+1
        %rotate 1
    %endrep
    %xdefine stack_offset %%stack_offset
    %assign n_arg_names %0
%endmacro

Кажется, это искажение имени и добавление q в конце аргументов. Однако я не понимаю, почему в директивах %undef несколько строк, а в функции используется только имя переменной с суффиксом q. Кажется, в конце также добавляется число, но по какой-то причине я не вижу его в другом ассемблерном файле.

Что мне здесь не хватает?


person meneldal    schedule 16.06.2015    source источник


Ответы (1)


Макрос DEFINE_ARGS определяет ряд однострочных макросов, которые предназначены для использования для ссылки на аргументы функции, которую вводит макрос cglobal. Так, например, если в качестве имени первого аргумента указано foo, то DEFINE_ARGS создает следующие определения:

%xdefine fooq r0q
%xdefine food r0d
%xdefine foow r0w
%xdefine fooh r0h
%xdefine foob r0b
%xdefine foom r0m
%xdefine foomp r0mp

Суффиксы представляют, как должен быть получен доступ к аргументу. Первые пять суффиксов q, d, w, h,, b указывают размер: указатель (учетное или двойное слово), двойное слово, слово, байт и байт соответственно. Суффикс h указывает, что байт является старшей частью 16-битного значения. Суффикс m обращается к аргументу как к операнду в памяти неопределенного размера, а суффикс mp обращается к нему как к операнду в памяти с размером указателя.

Имена rNx, которые определяют эти макросы аргументов, сами по себе являются макросами. Они расширяются до регистра или области памяти для суффиксов m и mp, где хранится N-й аргумент. Таким образом, при сборке для 64-битной Windows макросы для первого аргумента эффективно:

%define r0q rcx
%define r0d ecx
%define r0w cx
%define r0h ch
%define r0b cl
%define r0m ecx
%define r0mp rcx

Обратите внимание, что, поскольку соглашение о вызовах 64-разрядной версии Windows передает первый аргумент в регистр (RCX), в памяти нет места, соответствующего этому аргументу.

При построении для 32-битных целей первый аргумент макроса rNx заканчивается следующим образом:

%define r0q eax
%define r0d eax
%define r0w ax
%define r0h ah
%define r0b al
%define r0m [esp + stack_size + 4]
%define r0mp dword [esp + stack_size + 4]

Макрос r0q в этом случае обращается только к 32-битному регистру, потому что 64-битные регистры недоступны в 32-битном коде. Поскольку этот первый аргумент передается в стек при соблюдении 32-битных соглашений о вызовах, код пролога, сгенерированный макросом cglobal, загружает первый аргумент в EAX.

Очевидно, код, который вы видели, который использует эти макросы аргументов, обращается только к аргументам размером с указатель, поэтому вы видите только суффиксы q.

Назначение строк %undef в начале макроса DEFINE_ARGS состоит в том, чтобы отменить определение макросов аргументов, определенных предыдущим вызовом DEFINES_ARGS. В противном случае они останутся определенными в текущей функции. Имена аргументов предыдущей функции хранятся в однострочном макросе с именем arg_nameN.

Пожалуйста, не следуйте примеру кода, который вы читаете. По сути, они создают производный и уникальный язык программирования, который действительно понимают только авторы макросов. Это также не самый эффективный способ ведения дел. Если бы я писал этот код, я бы использовал C/C++ и его векторные встроенные функции. Это оставило бы компилятору все различия между 32-битной и 64-битной версиями, Windows и Linux, который мог бы генерировать код лучше, чем эти макросы.

person Ross Ridge    schedule 16.06.2015
comment
Ну, весь макрос, который заботится об обработке стека для вас, довольно хорош из того, что я видел. Кажется, это намного лучше, чем встроенная сборка (и все проблемы с переносимостью, которые возникают с ней), хотя я согласен, если производительность не является проблемой, в этом нет необходимости. Большое спасибо за разъяснение всего этого, я желаю, чтобы потомки могли включить ваш ответ в комментарии. - person meneldal; 16.06.2015