X64 Windows NASM汇编代码在ReadConsole上给出了细分故障,这可能是由于堆栈对齐问题引起的

发布于 2025-02-01 05:15:08 字数 4791 浏览 1 评论 0原文

我正在Windows X64汇编中编写质数生成器。现在,我一直坚持要获得一个数字的用户输入以生成质数,直到为止。这被视为字符串,稍后将转换为int

当前,下面的代码一旦我以ReadConsole函数进入控制台(使用gdb),就会导致分割故障。

bits 64 ; Tell nasm to make 64-bit code
default rel ; Tell nasm to use rip-relative addressing. (Instruction pointer relative).

global main ; Export this

; Import these
extern printf
extern getchar
extern scanf
extern ExitProcess
extern GetStdHandle
extern ReadConsoleA

segment .bss ; uninitialised mutable data.
    ; resb - "reserve byte"
    chartest: resb 1 ; char is 1 bytes
    towhatnumberresponse: resb  4   ; reserve an int with name towhatnumberresponse
    consoleinputhandle: resb 8 ; windows needs this for dumb reasons.
    intstringread: resb 10 ; string read from console
    intstring_as_int: resb 4 ; and converted to int stored here.

segment .data ; initialised read/write data.
    STD_INPUT_HANDLE equ -10
    NULL             equ 0
    printint db "%d", 0xd, 0xa, 0x0 ; 0xd, 0xa is the CRLF line terminator
    printchar db "%c", 0xd, 0xa, 0x0
    printstring db "%s %s, %s, %s", 0xd, 0xa, 0x0
    genorcheck db "Would you like to generate prime numbers (G) or check if a number is prime (C)? ", 0x0
    towhatnumber db "To what number would you like to generate primes to? ", 0x0
    gentowhatnuminput db "%6d", 0x0

segment .text ; Where code is
    ; Function initialisation where we 'allocate' the shadow space required by
    ; Windows. Refer to https://sonictk.github.io/asm_tutorial/#windows:thewindowtothehardware/themicrosoftx64callingconvention/theshadowspace
    push   rbp
    mov    rbp, rsp
    sub    rsp, 32

    lea rcx, [genorcheck] ; print genorcheck
    call printf

    xor rcx, rcx
    call getchar

    cmp rax, 'G' ; no ignoring here pls, compare with rax instead.
    je generate_primes ; jump if equal (rax with 'G')
    cmp rax, 'C'
    je check_prime_num
    ; if none of G or C, then exit
    add rsp, 32
    pop rbp
    ret

generate_primes:
    push rbp
    mov  rbp, rsp
    sub  rsp, 64

    lea rcx, [towhatnumber] ; printf(towhatnumber);
    call printf

    mov rcx, STD_INPUT_HANDLE ; value of -10
    call GetStdHandle

    mov      [consoleinputhandle], QWORD rax ; store handle into consoleinputhandle

    mov rcx, rax ; hConsoleInput
    lea rdx, [intstringread] ; lpBuffer
    mov r8, 9 ; nNumberOfCharsToRead. 1 less than space for a zero
    mov r9, NULL ; lpNumberOfCharsRead: useless
    push NULL ; pInputControl: unneeded.
    call ReadConsoleA ; segfault when input is given after this call.
    ; just refer to this for anything
    ; https://github.com/jacwil/nasm-on-windows/blob/master/01_helloworld/win64/hello64.asm

    cmp rax, 0 ; ReadConsoleA only returns 0 on error, non-zero otherwise
    je error ; just sets return value to 20 and exits.


    lea rcx, [intstringread]
    call printf

    lea rcx, [printstring]
    lea rdx, [intstringread]
    xor rax, rax
    add rsp, 64
    pop rbp,
    ret

check_prime_num:
    jmp exit

exit:
    xor rcx, rcx ; ExitProcess(0) signals success
    call ExitProcess

error:
    mov rcx, 20
    call ExitProcess

我认为问题可能是由于堆栈对齐问题引起的,或者没有给出足够的堆栈空间,但是我根本无法掌握这个概念(尽管有4天的阅读理论)。我已经检查了gcc -s示例C程序的输出:

#include <stdlib.h>
#include <stdio.h>
#include <Windows.h>
#include <winbase.h>

char intasstring[11] = {0};
char buf[7] = {0};

void G();
int main(void)
{
    G();
    return 0;
}

void G() {
    printf("To what number? ");
    ReadConsole(GetStdHandle(STD_INPUT_HANDLE), &buf, 6, NULL, NULL);
    printf("%s", intasstring);
}

它使用了

sub    rsp, 80

我尝试但没有更改任何内容的方法。任何帮助都将不胜感激,因为我花了2天的时间试图解决这个问题。

segfault拆卸:

0x00007ffc696fe4c5  ? mov    DWORD PTR [r15],eax
0x00007ffc696fe4c8  ? test   r14b,r14b
0x00007ffc696fe4cb  ? je     0x7ffc696fe4de <ReadConsoleA+494>
0x00007ffc696fe4cd  ? shr    eax,1
0x00007ffc696fe4cf  ? mov    DWORD PTR [r15],eax
0x00007ffc696fe4d2  ? test   rbx,rbx
0x00007ffc696fe4d5  ? je     0x7ffc696fe4de <ReadConsoleA+494>
0x00007ffc696fe4d7  ? mov    eax,DWORD PTR [rsp+0x64]
0x00007ffc696fe4db  ? mov    DWORD PTR [rbx+0xc],eax
0x00007ffc696fe4de  ? cmp    ecx,0x101

此时注册信息:

rax 0x0000000000000001         rbx 0x0000000000000000
rcx 0x0000000000000000         rdx 0x0000000000000000
rsi 0x0000000000000009         rdi 0x0000000000000011
rbp 0x000000e650dffd08         rsp 0x000000e650dffb38
r8 0x000000e650dff9d0          r9 0x000000e650dffad8
r10 0x0000000000000000         r11 0x0000000000000246
r12 0x00007ff7e7e3300d         r13 0x00000000000001a4
r14 0x0000000000000000         r15 0x0000000000000000
rip 0x00007ffc696fe4c5

I am writing a prime number generator in Windows x64 assembly. Right now I am stuck at getting user input of a number to generate prime numbers until. This is taken as a string and will be converted into an int later.

Currently the code below causes a Segmentation Fault as soon as I enter a character into the console at the ReadConsole function (using gdb).

bits 64 ; Tell nasm to make 64-bit code
default rel ; Tell nasm to use rip-relative addressing. (Instruction pointer relative).

global main ; Export this

; Import these
extern printf
extern getchar
extern scanf
extern ExitProcess
extern GetStdHandle
extern ReadConsoleA

segment .bss ; uninitialised mutable data.
    ; resb - "reserve byte"
    chartest: resb 1 ; char is 1 bytes
    towhatnumberresponse: resb  4   ; reserve an int with name towhatnumberresponse
    consoleinputhandle: resb 8 ; windows needs this for dumb reasons.
    intstringread: resb 10 ; string read from console
    intstring_as_int: resb 4 ; and converted to int stored here.

segment .data ; initialised read/write data.
    STD_INPUT_HANDLE equ -10
    NULL             equ 0
    printint db "%d", 0xd, 0xa, 0x0 ; 0xd, 0xa is the CRLF line terminator
    printchar db "%c", 0xd, 0xa, 0x0
    printstring db "%s %s, %s, %s", 0xd, 0xa, 0x0
    genorcheck db "Would you like to generate prime numbers (G) or check if a number is prime (C)? ", 0x0
    towhatnumber db "To what number would you like to generate primes to? ", 0x0
    gentowhatnuminput db "%6d", 0x0

segment .text ; Where code is
    ; Function initialisation where we 'allocate' the shadow space required by
    ; Windows. Refer to https://sonictk.github.io/asm_tutorial/#windows:thewindowtothehardware/themicrosoftx64callingconvention/theshadowspace
    push   rbp
    mov    rbp, rsp
    sub    rsp, 32

    lea rcx, [genorcheck] ; print genorcheck
    call printf

    xor rcx, rcx
    call getchar

    cmp rax, 'G' ; no ignoring here pls, compare with rax instead.
    je generate_primes ; jump if equal (rax with 'G')
    cmp rax, 'C'
    je check_prime_num
    ; if none of G or C, then exit
    add rsp, 32
    pop rbp
    ret

generate_primes:
    push rbp
    mov  rbp, rsp
    sub  rsp, 64

    lea rcx, [towhatnumber] ; printf(towhatnumber);
    call printf

    mov rcx, STD_INPUT_HANDLE ; value of -10
    call GetStdHandle

    mov      [consoleinputhandle], QWORD rax ; store handle into consoleinputhandle

    mov rcx, rax ; hConsoleInput
    lea rdx, [intstringread] ; lpBuffer
    mov r8, 9 ; nNumberOfCharsToRead. 1 less than space for a zero
    mov r9, NULL ; lpNumberOfCharsRead: useless
    push NULL ; pInputControl: unneeded.
    call ReadConsoleA ; segfault when input is given after this call.
    ; just refer to this for anything
    ; https://github.com/jacwil/nasm-on-windows/blob/master/01_helloworld/win64/hello64.asm

    cmp rax, 0 ; ReadConsoleA only returns 0 on error, non-zero otherwise
    je error ; just sets return value to 20 and exits.


    lea rcx, [intstringread]
    call printf

    lea rcx, [printstring]
    lea rdx, [intstringread]
    xor rax, rax
    add rsp, 64
    pop rbp,
    ret

check_prime_num:
    jmp exit

exit:
    xor rcx, rcx ; ExitProcess(0) signals success
    call ExitProcess

error:
    mov rcx, 20
    call ExitProcess

I think the problem may be due to stack alignment issues or not giving enough stack space but I just can't get my head around this concept at all (despite 4 days of reading theory). I've checked gcc -S output of an example C program:

#include <stdlib.h>
#include <stdio.h>
#include <Windows.h>
#include <winbase.h>

char intasstring[11] = {0};
char buf[7] = {0};

void G();
int main(void)
{
    G();
    return 0;
}

void G() {
    printf("To what number? ");
    ReadConsole(GetStdHandle(STD_INPUT_HANDLE), &buf, 6, NULL, NULL);
    printf("%s", intasstring);
}

and it used

sub    rsp, 80

which I tried but didn't change anything. Any help would be appreciated as I've spent 2 days trying to figure this out.

Disassembly at Segfault:

0x00007ffc696fe4c5  ? mov    DWORD PTR [r15],eax
0x00007ffc696fe4c8  ? test   r14b,r14b
0x00007ffc696fe4cb  ? je     0x7ffc696fe4de <ReadConsoleA+494>
0x00007ffc696fe4cd  ? shr    eax,1
0x00007ffc696fe4cf  ? mov    DWORD PTR [r15],eax
0x00007ffc696fe4d2  ? test   rbx,rbx
0x00007ffc696fe4d5  ? je     0x7ffc696fe4de <ReadConsoleA+494>
0x00007ffc696fe4d7  ? mov    eax,DWORD PTR [rsp+0x64]
0x00007ffc696fe4db  ? mov    DWORD PTR [rbx+0xc],eax
0x00007ffc696fe4de  ? cmp    ecx,0x101

Register info at this point:

rax 0x0000000000000001         rbx 0x0000000000000000
rcx 0x0000000000000000         rdx 0x0000000000000000
rsi 0x0000000000000009         rdi 0x0000000000000011
rbp 0x000000e650dffd08         rsp 0x000000e650dffb38
r8 0x000000e650dff9d0          r9 0x000000e650dffad8
r10 0x0000000000000000         r11 0x0000000000000246
r12 0x00007ff7e7e3300d         r13 0x00000000000001a4
r14 0x0000000000000000         r15 0x0000000000000000
rip 0x00007ffc696fe4c5

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文