当我“退回”时为什么会出现段错误? (FASM)

时间:2016-10-09 20:40:19

标签: linux assembly return x86-64 fasm

通过一些操作,我已将其缩小到ret操作的问题。我知道call将返回地址推送到堆栈;弹出并将其推回是违法的吗?

format ELF64 executable 3

entry start

segment readable executable

start:
    pop rcx         ; argc
    mov [argc],cl       ; int -> ASCII
    add [argc],'0'
    push 1 argc 1
    call sys_write

    mov rdi,0
    mov rax,60
    syscall

sys_write: ; (fd,*buf,count)
    pop r11
    pop rdx rsi rdi
    mov rax,1
    syscall
    push r11
    ret

segment readable writable

argc rb 1

输出是:

$ ./prog
1Segmentation fault
$ _

1 个答案:

答案 0 :(得分:1)

syscall指令使用R11注册表隐含了RFLAGS的内容,这意味着在syscall R11之后存储的值是syscall覆盖。

解决方案可能只是选择一个未被系统调用修改的适当寄存器。根据英特尔的说明参考手册(http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-manual-325462.pdf,第4-668页第2B卷)RCX覆盖RIPR11RFLAGS和{{1}作为其操作的一部分,但操作系统当然能够恢复RIP和RFLAGS。

这留下了很多其他选择。一个很好的选择是一个寄存器,允许函数调用在标准的用户空间调用约定中被破坏,但Linux系统调用将保持不变。 R8符合要求。由于您未使用标准x86-64 System V function-calling conventionRBXRBP将是更好的选择(较小的机器代码大小,因为它们不需要REX前缀)。