printf 给出分段错误?

printf gives segmentation fault?

我(正如您可能已经猜到的那样)是 nasm 编码的新手,我正在尝试在 nasm 程序集中编写类似于此的简单组合程序(计算组合 (nCr))我制作的C代码:

#include <stdio.h>

int main(int argc, char const *argv[])
{        
    int n = 9;
    int r = 2;
    int i = 0;
    int npr = 1;
    int rfac = 1;
    int k = n;
    //nPr
    while (i<r)
    {
        npr = npr*(k);
        k--;
        i++;
    }
    //r!
    while(r>0)
    {
        rfac = rfac*r;       
        r--;
    }
    //nPr/r! = nCr
    printf("%d\n", npr/rfac);
return 0;
}

我的仿汇编代码在nasm:

        extern printf

        SECTION .data


fmt:    db "%d", 10, 0  ;format for printf (used once)

n:  dq  10              ; 64 bit double var n = 10.000
r:  dq  2               ; 64 bit int var r = 3
i:  dq  0               ; 64 bit int var i = 0
npr:  dq  1             ; 64 bit double var npr = 1.000
rfac:   dq  1           ; 64 bit int var npr = 1


        SECTION .text   ; code section
        global main

main:
        push rbp        ; base pointer
        mov rax,[npr]   ; load npr
        mov rbx,[i]     ; load i
        mov rcx,[n]     ; load n
        mov rdx,[r]     ; load r for condition checking 
        ;sub rdx,[r]     ; subtract n - r
        ;sub rdx,1       ; subtract (n = n-r) - 1. now we can compare it to rdx

        jmp loop1       ; Jump to condition first
cloop1  imul rax,rcx    ; multiply the word npr with n
        dec rcx         ; decrement n
        inc rbx         ; increment i
loop1   cmp rbx,rdx     ; Check the condition
        jl cloop1       ; Jump to content of the loop if met

        mov rdx,[r]     ; load r
        mov rcx,[rfac]  ; load rfac
        mov rbx,0       ; set rbx to 0
        jmp loop2       ; Jump to condition first
cloop2  imul rcx,rdx    ; multiply the word rfac with r
        dec rdx         ; decrement r
loop2   cmp rbx,rdx     ; Check the condition(0<=r)
        jl cloop2       ; Jump to content of the loop if met
diva:   
        mov rdx,0
        mov rax,rax
        idiv rcx        ; divide rax(npr) by rcx(rfac)
        mov rsi,rax     ; 1st printf var
        xor rax,rax     ; make it 0?
        call printf     ; call the function
        
        pop rbp         ; pop the stack
        mov rax,0       ; exit code
        ret             ; return to OS from main

它一直给我段错误,所以我调试了它:

diva () at ncr.asm:43
43              mov rdx,0
(gdb) info registers
rax            0x5a     90
rbx            0x0      0
rcx            0x2      2
rdx            0x0      0
rsi            0x7ffffffedec8   140737488281288
rdi            0x1      1
rbp            0x400570 0x400570 <__libc_csu_init>
rsp            0x7ffffffedde0   0x7ffffffedde0
r8             0x7fffff3ecd80   140737475693952
r9             0x7fffff3ecd80   140737475693952
r10            0x2      2
r11            0x7      7
r12            0x400400 4195328
r13            0x7ffffffedec0   140737488281280
r14            0x0      0
r15            0x0      0
rip            0x400545 0x400545 <diva>
eflags         0x246    [ PF ZF IF ]
cs             0x33     51
ss             0x2b     43
ds             0x0      0
es             0x0      0
fs             0x0      0
gs             0x0      0
(gdb) next
44              mov rax,rax
(gdb) next
45              idiv rcx        ; divide rax(npr) by rcx(rfac)
(gdb) next
46              mov rsi,rax     ; 1st printf var
(gdb) next
47              xor rax,rax     ; make it 0?
(gdb) next
48              call printf     ; call the function
(gdb) next

Program received signal SIGSEGV, Segmentation fault.
__strchrnul_avx2 () at ../sysdeps/x86_64/multiarch/strchr-avx2.S:57
57      ../sysdeps/x86_64/multiarch/strchr-avx2.S: No such file or directory.
(gdb)

据我所知,循环很好,当我调用 printf 函数时它给了我段错误。

我在某些地方看到他们推送格式,然后推送函数,然后调用它。我试过了,但我想我做错了。 如果您觉得对我的改进有建设性,欢迎对我的代码提出任何建议/批评和彻头彻尾的亵渎。

编辑:将“%f”更改为“%d”,这些是调用 printf 之前寄存器中的值:

(gdb) next
48              call printf     ; call the function
(gdb) info registers
rax            0x0      0
rbx            0x0      0
rcx            0x2      2
rdx            0x0      0
rsi            0x2d     45
rdi            0x1      1
rbp            0x400570 0x400570 <__libc_csu_init>
rsp            0x7ffffffedde0   0x7ffffffedde0
r8             0x7fffff3ecd80   140737475693952
r9             0x7fffff3ecd80   140737475693952
r10            0x2      2
r11            0x7      7
r12            0x400400 4195328
r13            0x7ffffffedec0   140737488281280
r14            0x0      0
r15            0x0      0
rip            0x400556 0x400556 <diva+17>
eflags         0x246    [ PF ZF IF ]
cs             0x33     51
ss             0x2b     43
ds             0x0      0
es             0x0      0
fs             0x0      0
gs             0x0      0

我明白了!!!!

我做到了我终于解决了!!!

无论如何,这是我用过的东西:

而不是将格式推送为 push fmt

我反而阅读了 nasm 文档,看到了一些示例,发现我们必须将格式 fmt 存储在 rdi 中,并将变量按各自的顺序存储在 rsirdxrcxr8 等等。

所以我确实做到了,然后 BOOM!在执行时弹出答案。我的快乐无拘无束

修复代码:

        extern printf

        SECTION .data


fmt:    db "nCr = %d", 10, 0  ;format for printf (used once)

n:  dq  10              ; 64 bit double var n = 10.000
r:  dq  2               ; 64 bit int var r = 3
i:  dq  0               ; 64 bit int var i = 0
npr:  dq  1             ; 64 bit double var npr = 1.000
rfac:   dq  1           ; 64 bit int var npr = 1


        SECTION .text   ; code section
        global main

main:
        push rbp        ; base pointer
        mov rax,[npr]   ; load npr
        mov rbx,[i]     ; load i
        mov rcx,[n]     ; load n
        mov rdx,[r]     ; load r for condition checking 
        ;sub rdx,[r]     ; subtract n - r
        ;sub rdx,1       ; subtract (n = n-r) - 1. now we can compare it to rdx

        jmp loop1       ; Jump to condition first
cloop1  imul rax,rcx    ; multiply the word npr with n
        dec rcx         ; decrement n
        inc rbx         ; increment i
loop1   cmp rbx,rdx     ; Check the condition
        jl cloop1       ; Jump to content of the loop if met

        mov rdx,[r]     ; load r
        mov rcx,[rfac]  ; load rfac
        mov rbx,0       ; set rbx to 0
        jmp loop2       ; Jump to condition first
cloop2  imul rcx,rdx    ; multiply the word rfac with r
        dec rdx         ; decrement r
loop2   cmp rbx,rdx     ; Check the condition(0<=r)
        jl cloop2       ; Jump to content of the loop if met
diva:   
        mov rdx,0
        mov rax,rax
        idiv rcx        ; divide rax(npr) by rcx(rfac)
        mov rdi,fmt     ; storing format
        mov rsi,rax     ; 1st printf var
        mov rax,0       ; make it 0?        
        call printf     ; call the function
        
        pop rbp         ; pop the stack
        mov rax,0       ; exit code
        ret             ; return to OS from main