了解NASM宏

时间:2015-06-16 02:30:32

标签: assembly macros ffmpeg 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)中找到该宏:< / p>

%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后缀的变量名似乎在函数中使用。它似乎也在最后附加了一个数字但由于某种原因我没有在另一个asm文件中看到它。

我在这里缺少什么?

1 个答案:

答案 0 :(得分:3)

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

后缀表示应该如何访问参数。前五个qdwh,b后缀表示大小:指针(四字或双字),双字,字,字节和字节分别。 h后缀表示该字节是16位值的高位部分。 m后缀将参数作为未指定大小的内存操作数访问,而mp后缀将其作为指针大小的内存操作数访问。

这些参数宏定义为的rNx名称本身就是宏。它们扩展到mmp后缀的寄存器或内存位置,其中存储了 N 参数。因此,在为64位Windows构建时,第一个参数的宏是有效的:

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

请注意,由于Windows 64位调用约定传递了寄存器(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后缀的原因。

宏DEFINE_ARGS开头的%undef行的目的是取消定义先前调用的DEFINES_ARGS的参数宏。否则它们将在当前函数中保持定义。上一个函数的参数名称存储在一个名为arg_name N 的行宏中。

请不要按照您正在阅读的代码设置的示例进行操作。它们本质上创建了一种衍生和独特的编程语言,只有宏的作者才能真正理解它。它也不是最有效的做事方式。如果我正在编写这段代码,我会使用C / C ++及其向量内在函数。这将使32位和64位,Windows和Linux之间的所有差异留给编译器,这可能会生成比这些宏更好的代码。