【问题标题】:How do I printf and scanf in x86_64 assembly?如何在 x86_64 程序集中 printf 和 scanf?
【发布时间】:2021-02-14 00:22:13
【问题描述】:

该程序的目的是从用户那里获取 3 个参数和一个附加参数并求其总和。

我让它工作,以便它找到 3 个参数的总和并打印出总和。

如何打印不带参数的字符串以及如何获取用户的输入并打印该输入?

includelib legacy_stdio_definitions.lib
extrn printf:near, scanf:near

.data                           ; Data section

istr db 'Please enter an integer: '
stri byte '%lld', 0AH, 00
ostr byte 'The sum of proc. and user inputs (%lld, %lld, %lld, %lld): %lld', 0AH, 00

.code                           ; Code section

public use_scanf                ; int use_scanf(long long a, long long b, long long c)
use_scanf:                      ; { 

    mov rax, 0                  ; sum = 0;
    add rax, rcx                ; sum += a;
    add rax, rdx                ; sum += b;
    add rax, r8                 ; sum += c;

    ; printf('Please enter an integer');
    ; scanf();
    ; printf('%lld', &inp_int);


    mov r9, 3                   ; temp inp_int      
    add rax, r9                 ; sum += inp_int;

    push rbx                    ; save reg rbx to make space
    mov rbx, rax                ; save sum in rbx
    push rax                    ; sum.push
    push rax                    ; sum.push
    push r9                     ; usrinput.push
    sub rsp, 32                 ; allocate shadow space
    mov r9, r8                  ; arg3 = c;
    mov r8, rdx                 ; arg2 = b;
    mov rdx, rcx                ; arg1 = a
    lea rcx, ostr               ; arg0 = ostr;
    call printf                 ; printf(ostr);

    add rsp, 56                 ; clear shadow space and vars from stack
    mov rax, rbx                ; retVal = sum
    pop rbx                     ; return rbx to previous value

    ret                         ; return retVal}

编辑:控制台输出

Please enter an integer: 2
use_scanf_spill4 equ 12 * 8 ; The slots above return address that are
The sum of proc. and user inputs (1, 2, 3, 1002523588520): 1002523588526
use_scanf(1,2,3) = 73 ERROR: should be 7018134685179969542

Please enter an integer: 2
The sum of proc. and user inputs (-3, 2, -2, 1002523588520): 1002523588517
use_scanf(-3,2,-2) = 75 ERROR: should be 7018134685179969533

Please enter an integer: 3
The sum of proc. and user inputs (4, 3, -4, 1002523588520): 1002523588523
use_scanf(4,3,-4) = 74 ERROR: should be 7018134685179969539

Please enter an integer: -3
The sum of proc. and user inputs (-3, -3, -4, 1002523588520): 1002523588510
use_scanf(-3,-3,-4) = 76 ERROR: should be 7018134685179969526

下面是用来测试的cpp文件。

void check(const char *s, _int64 v, _int64 expected) {
std::cout << s << " = " << v;
if (v == expected) {
    std::cout << " OK";
}
else {
    std::cout << " ERROR: should be " << expected;
}
std::cout << "\n";
}

_int64 sum_scanf;
_int64 sum_check;
sum_scanf = use_scanf(1, 2, 3);
sum_check = 1 + 2 + 3 + inp_int;
check("use_scanf(1,2,3)", sum_scanf, sum_check);
std::cout << "\n";
sum_scanf = use_scanf(-3, 2, -2);
sum_check = -3 + 2 - 2 + inp_int;
check("use_scanf(-3,2,-2)", sum_scanf, sum_check);
std::cout << "\n";
sum_scanf = use_scanf(4, 3, -4);
sum_check = 4 + 3 - 4 + inp_int;
check("use_scanf(4,3,-4)", sum_scanf, sum_check);
std::cout << "\n";
sum_scanf = use_scanf(-3, -3, -4);
sum_check = -3 - 3 - 4 + inp_int;
check("use_scanf(-3,-3,-4)", sum_scanf, sum_check);

【问题讨论】:

    标签: windows assembly printf scanf x86-64


    【解决方案1】:

    您有调用约定问题。首先,堆栈深度除以 8 必须是偶数。其次,除了序言和尾声,你不要使用 push 和 pop。

    我猜你从一个基本的 C 实现开始,反汇编它,然后开始编辑。编译器在这里提取了一些高级技巧,你最好在这个早期阶段避免。所以开始重写吧。

    我没有尝试优化任何东西。

    ;Take your globals from above -- you will need
    
    use_scanf_spill4 equ 12 * 8 ; The slots above return address that are
    use_scanf_spill3 equ 11 * 8 ; for spilling arguments. In theory you can
    use_scanf_spill2 equ 10 * 8 ; use them for something else but I didn't.
    use_scanf_spill1 equ 9 * 8
    use_scanf_space equ 7 * 8 ; it holds return addess -- don't clobber
    use_scanf_sum equ 6 * 8
    use_scanf_input equ 5 * 8
    use_scanf_arg6 equ 5 * 8 ; same as use_scanf_input, but only 1 is used at a time
    use_scanf_arg5 equ1 4 * 8
    ; 0, 1, 2, 3 are argument zone
    use_scanf:
            ; Allocate stack space
            ; this function doesn't use any non-call-clobbered registers
            sub  rsp, use_scanf_space
    
            ; spill input since we need it later
            mov [rsp + use_scanf_spill1], rcx
            mov [rsp + use_scanf_spill2], rdx
            mov [rsp + use_scanf_spill3], r8
            mov [rsp + use_scanf_spill4], r9
            
            ; Add arguments together and stash
            add  rcx, rdx
            add  rcx, r8
            mov  [rsp + use_scanf_sum], rcx
    
            ; print the promot
            lea  rcx, istr
            call printf
    
            ; call scanf
            lea  rcx, [stri]
            ; Can't take the address of a register so we give it a memory slot
            lea  rdx, [rsp + use_scanf_input]
            call scanf
            
            ; sum the values
            mov  rdx, [rsp + use_scanf_sum]
            mov  rax, [rsp + use_scanf_input]
            add  rax, rdx
    
            ; print out the arguments and total
            ; using rcx as scratch -- will clobber later
            mov  rdx, [rsp + use_scanf_spill1]
            mov  r8,  [rsp + use_scanf_spill2]
            mov  r9,  [rsp + use_scanf_spill3]
            mov  rcx, [rsp + use_scanf_input]
            mov  [rsp + use_scanf_arg5], rcx
            mov  [rsp + use_scanf_arg6], rax
            lea   rcx, [ostr]
            call  printf
    
            ; now leave
            add  rsp, use_scanf_space
            ret
    

    【讨论】:

    • 首先,非常感谢您抽出宝贵的时间来做这件事,真的很重要。此外,当我运行程序时,它会自动输入 2 而不是让我输入整数,我无法与控制台交互,直到我右键单击显示所有内容的鼠标。我将编辑主要帖子以包含输出。
    • 忘记补充了,有一个名为 inp_int 的全局变量会在用户输入整数时发生变化
    • @AzureBlue62:你已经重定向了标准输入,我已经提供了足够的帮助。
    猜你喜欢
    • 1970-01-01
    • 2021-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-17
    • 1970-01-01
    • 1970-01-01
    • 2017-07-15
    相关资源
    最近更新 更多