x86 程序集:尝试反向打印阵列时出现分段错误(核心转储)



在我的代码中,我试图反向打印一个数组。 我的两个主要想法是使用堆栈和 LIFO 属性来执行此操作,或者使用循环作为从 10 到 0 零的索引来反向访问元素。由于堆栈方法的对齐问题,我选择了第二个。

我对组装很陌生,希望得到一些帮助,以了解我的错误在哪里。提前感谢!

DEFAULT REL
; external functions for inputs/outputs printf and scanf/printf
extern printf
extern scanf
section .data
prompt      db "Entrez un entier : ",0
longIntFormat  db "%ld",0

section .bss
entier resb 10       ; array of 10 integers

section.text
push rbp
mov rcx, 0  
mov rdx, 0     ; initialise counter
lea rcx, [entier]    ; load array into register rcx
; fills the array with user input
_getLoop:
; call printf
lea rdi,[prompt]
mov rax,0
call printf wrt ..plt
; call scanf
lea rdi,[longIntFormat]
lea rsi, [rcx + rdx]     ; array + Index
mov rax,0
call scanf wrt ..plt
inc rdx                      ; inc. Index/counter
cmp rdx, 10
jl _getLoop                  ; While counter is less than 10 (size of array)
mov rcx, 0          ; set rcx to 0
mov rdx, 10         ; counter set to 10
lea rcx, [entier]   ; load array into rcx
; print the array in reverse using the counter as Index
_printLoop:
; call printf
lea rdi, [rcx + rdx]     ; rdi = [array + Index]
mov rax,0
call printf wrt ..plt
dec rdx
cmp rdx, 0               ; compare counter with 0
jge _printLoop           ; Once 0 is reached the loop has gone through all the array
;restores registers
pop rbp
; returns 0 to C program
mov     rax, 0            
ret

有很多错误,例如:

  • 一个函数可以根据调用约定更改多个寄存器
  • scanfprintf格式字符串的语法略有不同。如果您打算修改printf输出(例如,使用n(,则必须创建另一个格式字符串。
  • 在你的循环中,你忘记了将任何格式的字符串传递给printf,只是一个整数的地址。 (printf 需要一个格式字符串,并按值获取整数。
  • "%ld"的意思是"长整数"。在我的系统上,这是一个四字(8 字节(。您严格只处理一个字节。
  • 在调用函数之前,堆栈必须对齐到 16 的倍数。 内核遵循 x86-64 System V ABI,并确保在进程入口时就是这种情况(通常入口点称为_start(。 如果按下/弹出,请确保在调用之前不会使堆栈未对齐。
  • _start(进程入口点(不是一个函数;你不能从中ret。 调用 glibc 的exit函数以确保刷新 stdio 缓冲区,或进行原始_exit系统调用。
  • section.text缺少空格。 它被解析为标签名称,如foo.bar:,而不是切换到.text部分的指令。 因此,您的代码最终进入了.data(或者可能以某种方式.bss(,并且由于这些部分链接到不可执行的内存页而出现段错误。

看看我更正的 - 现在工作 - 程序:

DEFAULT REL
; external functions for inputs/outputs printf and scanf/printf
extern printf, fflush
extern scanf
section .data
prompt      db "Entrez un entier : ",0
longIntFormat  db " %ld",0

section .bss
entier resq 10              ; array of 10 integers

global _start
section .text
_start:
;and rsp, -16                ; Align stack to 16 (the ABI already guarantees this for _start)
mov rbx, 0                  ; initialise counter
; fills the array with user input
_getLoop:
; call printf
lea rdi,[prompt]
mov rax,0
call printf wrt ..plt
; call scanf
lea rdi,[longIntFormat]
lea rsi, [entier + rbx * 8]    ; array + Index
mov rax,0
call scanf wrt ..plt
inc rbx                     ; inc. Index/counter
cmp rbx, 10
jl _getLoop                 ; While counter is less than 10 (size of array)
mov rbx, 9                  ; counter set to 10
; print the array in reverse using the counter as Index
_printLoop:
; call printf
lea rdi,[longIntFormat]
mov rsi, [entier + rbx*8]   ; rdi = [array + Index]
mov rax,0
call printf wrt ..plt
dec rbx
cmp rbx, 0                  ; compare counter with 0
jge _printLoop
xor edi, edi                ; RDI=0: all streams
call fflush  wrt ..plt
mov rax,60                  ; SYS_EXIT
mov rdi,0                   ; Exitcode: RDI=0
syscall                     ; Call Linux64

最新更新