linux nasm汇编中调用printf不报错,但调用scanf报错。抛出了分段错误(核心转储)

当我写了如下汇编时

bash 复制代码
; nasm -f elf64 -g -F dwarf charsin.asm
; gcc charsin.o -no-pie -o charsin
; ld -o eatclib eatclib.o
; gdb eatclib


[SECTION .data]
  SPrompt db 'Enter string data, followed by Enter: ',0
  IPrompt db 'Enter an integer value, followed by Enter: ',10,0
  IFormat db "%d",0
  SShow db 'The string you entered was: %s',0
  IShow db 'The Integer value you entered was: %5d',10,0


[SECTION .bss]
 IntVal resd 1
 InString resb 128 


[SECTION .text]

 extern stdin
 extern fgets
 extern printf
 extern scanf
 global main

 main:
   
   push rbp
   mov rbp,rsp
   push rbx
   push rsi
   push rdi
   
   
   ;push SPrompt
   mov rdi,SPrompt ; 传递参数
   mov rax,0
   call printf
   ;add rsp,8
 
   ; rdi,rsi,rdx,rcx分别保存第1,2,3,4个参数
   ;push qword [stdin]
   ;push 72
   ;push InString
   mov rdi,InString
   mov rsi,72
   mov rdx,[stdin]
   mov rax,0
   call fgets
   ;add rsp,24
   
   ;push InString
   ;push SShow
   mov rdi,SShow
   mov rsi,InString
   ;在汇编代码中,若是调用变长参数的函数,需要使用al这个寄存器记录使用到的向量寄存器数量。
   ;这段代码中eax中存放的不是系统调用号,存放的是向量寄存器使用到的数量0,因为printf使用的是变长参数。
   mov rax,0
   call printf
   ;add rsp,16
   
   mov rax,0
   push IPrompt
   mov rdi,IPrompt ; 传递参数
   call printf
   add rsp,8
   
   ;push IntVal
   ;push IFormat
   mov rdi,IFormat 
   mov rsi,IntVal ; 保留数字的内存地址
   xor rax,rax
   call scanf
   ;add rsp,16
   
   ;mov rax, 0  ;sys_read 系统调用号
   ;mov rdi, 0  ; 文件描述符 标准输入
   ;mov rsi,IntVal ; 保留数字的内存地址
   ;mov rdx, 4
   ;syscall
   
   xor rsi,rsi
   mov rax,0
   mov rdi,IShow ; 传递格式参数
   mov esi,[IntVal]
   call printf
   ;add rsp,16
  
  pop rdi
  pop rsi
  pop rbx
  mov rsp,rbp
  pop rbp
  
  
  ret

编译后,系统会如下段错误(Segmentation fault (core dumped)).

在函数的开始/结束处使用 sub rsp, 8/add rsp, 8 将堆栈重新对齐到 16函数执行调用之前的字节。

bash 复制代码
; nasm -f elf64 -g -F dwarf charsin.asm
; gcc charsin.o -no-pie -o charsin
; ld -o eatclib eatclib.o
; gdb eatclib


[SECTION .data]
  SPrompt db 'Enter string data, followed by Enter: ',0
  IPrompt db 'Enter an integer value, followed by Enter: ',10,0
  IFormat db "%d",0
  SShow db 'The string you entered was: %s',0
  IShow db 'The Integer value you entered was: %5d',10,0


[SECTION .bss]
 IntVal resd 1
 InString resb 128 


[SECTION .text]

 extern stdin
 extern fgets
 extern printf
 extern scanf
 global main

 main:
   
   push rbp
   mov rbp,rsp
   push rbx
   push rsi
   push rdi
   
   ;在函数的开始/结束处使用 sub rsp, 8/add rsp, 8 将堆栈重新对齐到 16函数执行调用之前的字节。
   sub rsp, 8
   
   ;push SPrompt
   mov rdi,SPrompt ; 传递参数
   mov rax,0
   call printf
   ;add rsp,8
 
   ; rdi,rsi,rdx,rcx分别保存第1,2,3,4个参数
   ;push qword [stdin]
   ;push 72
   ;push InString
   mov rdi,InString
   mov rsi,72
   mov rdx,[stdin]
   mov rax,0
   call fgets
   ;add rsp,24
   
   ;push InString
   ;push SShow
   mov rdi,SShow
   mov rsi,InString
   ;在汇编代码中,若是调用变长参数的函数,需要使用al这个寄存器记录使用到的向量寄存器数量。
   ;这段代码中eax中存放的不是系统调用号,存放的是向量寄存器使用到的数量0,因为printf使用的是变长参数。
   mov rax,0
   call printf
   ;add rsp,16
   
   mov rax,0
   push IPrompt
   mov rdi,IPrompt ; 传递参数
   call printf
   add rsp,8
   
   ;push IntVal
   ;push IFormat
   mov rdi,IFormat 
   mov rsi,IntVal ; 保留数字的内存地址
   xor rax,rax
   call scanf
   ;add rsp,16
   
   ;mov rax, 0  ;sys_read 系统调用号
   ;mov rdi, 0  ; 文件描述符 标准输入
   ;mov rsi,IntVal ; 保留数字的内存地址
   ;mov rdx, 4
   ;syscall
   
   xor rsi,rsi
   mov rax,0
   mov rdi,IShow ; 传递格式参数
   mov esi,[IntVal]
   call printf
   ;add rsp,16
  
  ;在函数的开始/结束处使用 sub rsp, 8/add rsp, 8 将堆栈重新对齐到 16函数执行调用之前的字节。
  add rsp, 8
  
  pop rdi
  pop rsi
  pop rbx
  mov rsp,rbp
  pop rbp
  
  
  ret

编译后,程序运行正常。

参考段错误
StackOverflow

相关推荐
顶点多余1 天前
线程互斥+线程同步+生产消费模型
java·linux·开发语言·c++
李彦亮老师(本人)1 天前
Rocky Linux 9.x 安全加固实战指南:从系统初始化到生产级防护
linux·运维·安全·rocky
RisunJan1 天前
Linux命令-mount(用于挂载Linux系统外的文件)
linux·运维·服务器
国冶机电安装1 天前
其他弱电系统安装:从方案设计到落地施工的完整指南
大数据·运维·网络
蓝天守卫者联盟11 天前
玩具喷涂废气治理厂家:行业现状、技术路径与选型指南
大数据·运维·人工智能·python
脆皮炸鸡7551 天前
Linux开发工具~~~版本控制器Git以及调试工具GDB
linux·服务器·开发语言·经验分享·git·学习方法
hyunbar1 天前
Docker命令及使用指南
运维·docker·容器
无代码专家1 天前
通过轻流 AI OA 系统实现行政成本优化——生产管理落地方案
运维·人工智能·云计算
马尔代夫哈哈哈1 天前
用户聊天室-测试报告
运维·服务器