x64:为什么这段代码给我“地址边界错误"? [英] x64: Why does this piece of code give me "Address boundary error"

查看:147
本文介绍了x64:为什么这段代码给我“地址边界错误"?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么下面的x64程序集给我地址边界错误"?仅当我在call _print_string之后添加代码时才会发生.我假设某些寄存器已被修改,但是一旦_print_string函数返回,就不应该将它们还原吗?

Why does the following x64 assembly give me "Address boundary error"? It only happens when I add code after call _print_string. I assume that some of the register have been modified but aren't they supposed to be reverted once the _print_string function returns?

我正在使用Mac OS X

obj_size = 8

.data
    hello_world: .asciz "hello world!"

.text
    .globl _main


_main:

    pushq %rbp
    movq %rsp, %rbp
    leaq hello_world(%rip), %rdi
    callq _print_string

    subq obj_size, %rsp
    movq 1, %rax
    movq %rax, obj_size(%rsp)

    addq obj_size, %rsp


    leave
    ret

C程序是:

void
print_string(char *str) 
{
    printf("%s\n", str);
}

推荐答案

此代码的问题非常简单.在使用AT& T语法的GNU汇编器中- 用作立即操作数的文字常量必须以$(美元符号)作为前缀,否则该常量将被视为内存操作数.

The issue with this code is pretty simple. In GNU Assembler using AT&T syntax - literal constants that are used as an immediate operand need to be prefixed with a $ (dollar sign) otherwise the constant is treated as a memory operand.

这些行都有这个问题:

subq obj_size, %rsp
movq 1, %rax
[snip]
addq obj_size, %rsp

在这些情况下,因为要使用常量obj_size1作为值(立即操作数)而不是内存引用.上面的说明应该是:

In these cases since you want to use the constants obj_size and 1 as a value (immediate operand) and not a memory reference. The instructions above should have been:

subq $obj_size, %rsp
movq $1, %rax
[snip]
addq $obj_size, %rsp

subq obj_size, %rsp试图从 RSP 中的值中减去内存地址0x8处的64位值. movq 1, %rax试图将内存地址0x1的64位值移动到 RAX 中.您的程序出错,因为无法读取OS/X上的那些内存位置.

subq obj_size, %rsp attempted to subtract the 64-bit value at memory address 0x8 from the value in RSP. movq 1, %rax attempted to move the 64-bit value at memory address 0x1 into RAX. Your program faulted since those memory locations on OS/X can't be read from.

可以在

A good article on the difference between AT&T syntax and Intel syntax can be found on IBM's website. In particular they have this difference listed:

在AT& T语法中,立即数操作数前面带有$;在Intel语法中,立即数不是.例如:Intel:push 4,AT& T:pushl $4

In AT&T syntax, immediate operands are preceded by $; in Intel syntax, immediate operands are not. For example: Intel: push 4, AT&T: pushl $4


要缩小此类问题的范围,使用调试器通常是有益的.在OS/X上,如果您不使用Xcode,则可以从命令行使用调试器 LLDB . 使用 LLDB 的教程可能会有用.在这种情况下,您可以将 LLDB 作为lldb ./nameofprogram运行,然后使用run命令允许它继续运行直到失败.然后,调试器将向您显示崩溃发生的汇编指令.


To narrow down problems like these it is often beneficial to use a debugger. On OS/X if you are not using Xcode you can use the debugger LLDB from the command line. A tutorial on using LLDB may be useful. In this case you could have run LLDB as lldb ./nameofprogram and then used the run command to allow it to continue until it failed. The debugger would have then shown you what assembly instruction the crash occurred at.

如果您想了解64位OS/X代码使用的调用约定

If you want to know the calling convention used by 64-bit OS/X code Apple defines it this way:

OS X x86-64函数调用约定与System V应用程序二进制接口AMD64体系结构处理器增补中描述的函数调用约定相同.

The OS X x86-64 function calling conventions are the same as the function calling conventions described in System V Application Binary Interface AMD64 Architecture Processor Supplement.

您可以找到System V应用程序二进制接口AMD64体系结构处理器补编此处.呼叫者和被呼叫者保存的寄存器列表可在图3.4:寄存器用法

You can find the System V Application Binary Interface AMD64 Architecture Processor Supplement here. The list of caller and callee saved registers can be found in Figure 3.4: Register Usage

这篇关于x64:为什么这段代码给我“地址边界错误"?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆