nasm,宏打印未按预期工作

nasm, macro print not working as expected

我正在从 C 文件调用一个用汇编语言编写的函数。 c 代码将两个指针传递给汇编函数。我在程序集中使用打印宏来检查地址的值和它们指向的元素。

这是C代码:

extern int nn_from_set(float *q, float *t, int q_length, int *s, int s_length);

int main()
{
    float *matrix_dyn = malloc(6*4*sizeof(float));
    int *s = malloc( 3 * sizeof(int))
    //the vectors are filled here
    //print their address, no problem here
    printf("t: %p, s: %p, sizeof int*: %u\n", matrix_dyn, s,  sizeof(matrix_dyn));
    //assembly function called
    printf("Prova: %d\n", nn_from_set(matrix_dyn, matrix_dyn, 3, s, 3));
    return 0;
}

下面是汇编代码,有点长

extern printf

%macro pabc 1           ; a "simple" print macro
section .data       
.strm db %1,0            ; %1 is first actual macro call

section .text

    ; push onto stack bacwards
    push dword [nnfs_int]                ; int a
    push dword .strm
    push dword nnfs_fmt_int              ; users string
    call printf                          ; call C function
    add esp, 12                           ; pop stack 3 * 4 bytes

%endmacro

    section .data
fmt: db "%s, dist: %e",10,0         ; format string for printf
nnfs_fmt: db "%s",10,0              ; format string for printf
nnfs_fmt_int:   db "%s %p",10,0     ; format string for int debug


    section .bss

nnfs_dst:   resd 1                  ; reserve 32-bit word
nnfs_tmp:   resd 1                  ; int tmp;
nnfs_index: resd 1                  ; reserve 32-bit, int index;  
nnfs_int:   resd 1

    section .text

; function to be translated is 
; int nearest_neighbor_from_set(float* q, float* t, int q_length, int* s, int s_length)

global nn_from_set

nnfs_q           equ     8
nnfs_t           equ     12
nnfs_q_length    equ     16
nnfs_s           equ     20
nnfs_s_length    equ     24

nn_from_set:
            ; -------------------------------------------
            ; Entrace sequence
            ; -------------------------------------------
            push    ebp         ; save base pointer
            mov     ebp, esp    ; point to current stack frame
            push    ebx         ; save general registers
            push    esi         
            push    edi

            mov ecx, [ebp + nnfs_t]     ; t
            mov edx, [ebp + nnfs_s]     ; s
            
            mov [nnfs_int], ecx         ; print t
            pabc "ecx, t: " 
            
            mov [nnfs_int], edx        ; print s 
            ;pabc "edx, s: "

            mov esi, [edx]              ; *s

            mov [nnfs_int], esi         ; print *s
            ;pabc "edx"
            
            add edx, 4
            mov esi, [edx]

            mov [nnfs_int], esi
            ;pabc "esi"
            
            ; fine di nn_from_set
            mov eax, 50         ; for test purpose

            ; ------------------------------------------
            ; Exit sequence
            ; ------------------------------------------

            pop     edi
            pop     esi
            pop     ebx
            mov     esp, ebp
            pop     ebp
            ret

我有两个问题,对于这个版本的代码,当我尝试编译时,它说 .strm 已经定义,每次我在第一次调用后尝试调用宏时都会这样。

第二个问题。 我这样更改宏:

 %macro pabc 1           ; a "simple" print macro

section .text

    ; push onto stack bacwards
    push dword [nnfs_int]                ; int a
    push dword nnfs_fmt_int              ; users string
    call printf                          ; call C function
    add esp, 8                           ; pop stack 2 * 4 bytes

%endmacro

我删除了 .strm 参数。格式字符串现在是:

nnfs_fmt_int:   db " reg %p",10,0

在这个版本中,宏的第一次调用打印正确,第二次出错。例如,我调用宏来打印两个指针的地址:

mov [nnfs_int], ecx         ; print t
pabc "ecx, t: " 

mov [nnfs_int], edx        ; print s 
pabc "edx, s: "

这是输出(第一行是从 C 文件打印出来的):

t: 0x8500008, s: 0x8500070, sizeof int*: 4
 reg 0x8500008
 reg 0xf7778898

t 的地址打印正确,s 的地址打印错误。如果我反转这两个调用。

mov [nnfs_int], edx         ; print s
pabc "ecx, t: " 

mov [nnfs_int], ecx        ; print t
pabc "edx, s: "

这是输出(第一行是从 C 文件打印出来的):

t: 0x93a0008, s: 0x93a0070, sizeof int*: 4
 reg 0x93a0070
 reg (nil)

S 打印正确,但 t 打印错误。

我不知道出了什么问题,我使用了相同的宏模式,直到现在它才给我带来任何问题。我用来创建这个宏的例子来自这里:http://www.csee.umbc.edu/portal/help/nasm/sample.shtml

根据标准调用约定,一些寄存器是调用者保存的,即eaxecxedx。因此,您不应期望通过 call printf 保留它们的价值。这大概就是为什么你打印错误的值。您可以在打印第一个之前将第二个推入堆栈,然后将其弹回以打印它。事实上,因为那些已经在堆栈上,你可以从那里重新加载:

mov ecx, [ebp + nnfs_t]     ; t
mov [nnfs_int], ecx         ; print t
pabc "ecx, t: " 

mov edx, [ebp + nnfs_s]     ; s
mov [nnfs_int], edx         ; print s 
pabc "edx, s: "

; reload since printing changed ecx and edx
mov ecx, [ebp + nnfs_t]     ; t
mov edx, [ebp + nnfs_s]     ; s