Разбиране на NASM Macro

Намерих този макрос в изходен файл на асемблиране и просто не мога да разбера как работи.

Така че първо се запознах с тази функция (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 суфикс изглежда се използва във функцията. Изглежда също така добавя число в края, но по някаква причина не го виждам в другия asm файл.

Какво ми липсва тук?


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