Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C程序集中的调用约定(64位)-scanf_C_Assembly_64 Bit_Printf_Scanf - Fatal编程技术网

C程序集中的调用约定(64位)-scanf

C程序集中的调用约定(64位)-scanf,c,assembly,64-bit,printf,scanf,C,Assembly,64 Bit,Printf,Scanf,我有一些使用scanf和printf的汇编代码,我遇到了一些问题。当这两个函数在同一代码中使用时,寄存器中的值似乎丢失。程序基本上加载一个数字并打印出来。我们使用 nasm -f elf64 file.asm && gcc -o file file.o && ./file 在linux上 这是我们的代码: extern printf extern scanf section .data a db "set: ", 0 b db "not set: ",

我有一些使用scanf和printf的汇编代码,我遇到了一些问题。当这两个函数在同一代码中使用时,寄存器中的值似乎丢失。程序基本上加载一个数字并打印出来。我们使用

nasm -f elf64 file.asm && gcc -o file file.o && ./file
在linux上

这是我们的代码:

extern printf
extern scanf
section .data

  a db "set: ", 0
  b db "not set: ", 0
  reading db "Please enter a number: ", 0
  message db "\n", 0
  printsent db "%s", 10, 0
  printint db "%d", 10, 0
  printchar db "%c", 10, 0

  readInt db "%d", 0
  input db "%d", 0

section .text
    global main

main:

hatta: 
push rbp,
mov  rbp, rsp,
push rbx,
xor  rax, rax,
mov  rdi, printsent,
mov  rsi, reading
call  printf,
pop  rbx,

xor  rax, rax,
mov  rdi, readInt,
call  scanf,
mov  rbx, rdi

push rbx,
xor  rax, rax,
mov  rdi, printint,

mov  rsi, rbx,
call  printf,
pop  rbx,

pop  rbp,
ret
奇怪的是,如果删除了行
mov rdi,printint,
,我们就得到了正确的值。然而,如果我们对printstation做同样的事情,我们会得到一个分割错误。有谁能告诉我们原因吗


谢谢

我不明白为什么这里有C标志,这里没有涉及C代码,但是对于你的问题:

据我所知,Linux glibc x64中对
printf(格式,参数)
的调用约定是rdi中的
格式,rsi中的
参数

如果删除
mov rdi,printssent,
则调用
printf(未定义,“请输入一个号码”)
。您没有在
rdi
中提供格式参数,而是在
printf
不知道这一点,并使用当时
rdi
中的任何内容。很可能是无效的内存地址,因此调用了
SIGSEGV


默认情况下,x86中的函数调用对参数应该是非破坏性的,尽管这不是必需的。标准库函数通常是。它们通过将参数推送到堆栈并在完成时重新加载来实现这一点


同样,当您调用
scanf(readInt,…)
时,它将在返回时恢复指向
readInt
的指针,该指针的内容与
rdi
中的
printint
相同。因此,删除行
mov rdi,printint,
无效,因为
rdi
包含指向所需格式的有效指针。

在使用
scanf
时有两个错误,可能基于一个错误的假设:您的意思似乎是
scanf
返回
rdi
中加载的数字,并且格式
“%d”
不需要进一步的参数。事实上,数字(如果扫描成功)会返回到第二个参数所指向的内存中。因此,以下更改使代码正常工作

pop  rbx,                              |  ;delete
                                       =  
xor  rax, rax,                         =  xor  rax, rax,
mov  rdi, readInt,                     =  mov  rdi, readInt,
                                       >  mov  rsi, rsp
call  scanf,                           =  call  scanf,
mov  rbx, rdi                          |  pop  rbx,

关于mov rdi行printint是否被删除,我们将获得正确的值-我对此表示怀疑。

您将不得不说明您拥有什么操作系统,因为调用约定不同。调用约定在常规函数和可变函数(如printf)之间也有所不同,所以请注意您阅读的信息。我想这是一个练习,因为我认为在汇编程序中编写这样的东西现在仍然没有意义。最简单的方法是编写相应的TIG C程序,使用您最喜欢的编译器,使用
-S
或等效的汇编程序对其进行编译。“默认情况下,x86中的函数调用应该不会破坏参数”-这对于Win64或UN*X x86_64上的64位x86都不是这样。用于参数传递的寄存器是临时寄存器,即使被调用函数实际上不接受任何参数,也可以被调用函数任意修改。@FrankH:此外,一般来说,即使对于32位调用约定,也不是这样。被调用方“拥有”它们的堆栈参数,并且可以自由地对它们进行重击。e、 g.对于使用相同数量的arg但值不同的tailcall:编译器实际上会这样做。或者就像暂存空间一样,但编译器通常不会这样做。如果要使用相同的堆栈参数进行另一次调用,则必须再次存储它们(除非过程间优化让您知道第一个被调用方选择不删除它们)