我在汇编源文件中遇到了这个宏,我无法弄清楚它是如何工作的。
首先我来看看这个函数(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文件中看到它。
我在这里缺少什么?
答案 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
后缀表示应该如何访问参数。前五个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
请注意,由于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之间的所有差异留给编译器,这可能会生成比这些宏更好的代码。