- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在使用类似汇编程序的 API(它不是真正的汇编程序,但它可以发出机器代码),我正在调试和玩弄它。它专门用于 System V x86_64 ABI,因此我将只讨论 SysV 调用约定等。
出于某种原因,当我为了测试目的发出一些像这样的人为设计的代码时
builder.emit_sub(rsp, 1);
builder.emit_movq_vr(reinterpret_cast<uint64_t>(&hello_world), rax);
builder.emit_call(rax);
builder.emit_add(rsp, 1);
builder.emit_ret();
在调用时发生段错误(在运行时,而不是在组装时),但是
builder.emit_movq_vr(reinterpret_cast<uint64_t>(&hello_world), rax);
builder.emit_jmp(rax);
成功就好了。失败点似乎在 call
指令处,但我不知道伪汇编程序出了什么问题。它可能会发出错误的操作码操作数或其他东西,但我不确定。原始发出的机器代码对于错误代码看起来像这样,以及它应该表示的操作码,如一些简单的调试语句打印的那样
sub 48 81 EC 01 00 00 00
movqvr 48 B8 63 80 AA 01 01 00 00 00
call FF D0
add 48 81 C4 01 00 00 00
ret C3
备注:movqvr
不是真正的指令[助记符];最后的 vr
对我来说只是一个调试注释,它是一种“将 imm64 移至 reg”的指令。
备注:sub
和add
是将堆栈对齐到 16 字节边界上,我认为这在这个 ABI 中是必需的。它们可以更好地写成 push rax
和 pop rax
(或者 pop rcx
如果 rax
是需要一个返回值),但忽略它,除非它是搞乱调用的(例如,如果 rsp
没有被正确修改)。
最佳答案
是的,在 System V ABI 中,堆栈在每个call
指令之前 与 16 字节边界对齐。因此,在函数入口处,它需要另外 8 个字节(而不是 1 个字节)才能到达下一个 16 字节边界。请记住,在 C 中,指针差异按 sizeof(type)
缩放,但在 asm 中它们不是。
是的,push rax
/pop rcx
将是一个不错的选择,如果它还不需要推送奇数,这就是 clang/LLVM 所做的调用保留寄存器或保留任何额外的堆栈空间。如果您确实需要为局部变量保留任何堆栈空间,请使用将使 rsp
保持 16 字节对齐的偏移量。
顺便说一句,当立即数适合符号扩展的 8 位值(即 if ((int8_t) imm == imm)
).此外,如果您需要添加/减去 +128,请注意 -128
适合 imm8,因此您可以添加 rsp,-128
(例如在奇数之后push
指令)。
如果您知道代码运行的地址,您应该使用call rel32
编码,而不是寄存器间接调用。但是你是对的,跳转到任意 64 位地址需要这个 mov r64, imm64
序列,而不是直接的 call
。
您是否使用调试器找出 hello_world
崩溃的地方?也许如果它调用 printf
(而不是 puts
),它会忘记将 al
归零(使用 xor eax,eax
) 以指示 XMM 寄存器中没有 FP args,所以 printf 可能使用了一些 16 字节 SSE 对齐所需的存储到堆栈?
RSP 甚至没有 qword 对齐是非常糟糕的,但我不希望它崩溃任何会崩溃的东西 8 字节对齐(但不是 16)。
关于c++ - 调用但不跳转到 rax 中的地址时出现段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47730624/
我目前正在通过反汇编一些 C 代码来学习 ASM。我感兴趣的一件事是 gcc 编译器生成这样的代码 movq %rax,%rax 这显然毫无意义。那么这样做的目的是什么? 我想知道是不是用来浪费几个C
我无法找到上述两种情况的具体信息,尽管听取了您的专家意见。 第一件事是:我知道间接 jmp 会损害分支预测,并且即使间接结果恒定,它仍然需要预测维护缓冲区和其他内容,所有这些都与绝对 jmp 相比。
我试图了解由编译器完成的x64程序集优化。 我在Windows 8.1上使用Release IDE将Visual Studio 2008 SP1构建为一个小型C ++项目。 其中一行包含以下汇编代码:
mov (%rax),%eax有什么区别和 mov %rax,%eax ?我确定这是一个简单的问题,但我在任何地方都找不到答案。 这是提示我的问题的原始代码: mov -0x8(%rbp),%r
我正在查看为这个简单的 x64 程序生成的程序集 Visual Studio: struct Point { int a, b; Point() { a = 0; b
在为 gcc 编译器的 -O2 优化运行一些测试时,我在函数的反汇编代码中观察到以下指令: data32 data32 data32 data32 nopw %cs:0x0(%rax,%rax,1)
这个问题已经有答案了: What does the R stand for in RAX, RBX, RCX, RDX, RSI, RDI, RBP, RSP? [duplicate] (2 个回答)
有人可以向我解释一下为什么我们将主函数@0x6f5中的rax中的值移至rdi,然后将值复制到rdi 到 get_v 的堆栈,然后将其移回 rax @0x6c8?。也许这是x86-64的约定,但我不明白
我正在使用类似汇编程序的 API(它不是真正的汇编程序,但它可以发出机器代码),我正在调试和玩弄它。它专门用于 System V x86_64 ABI,因此我将只讨论 SysV 调用约定等。 出于某种
这个问题在这里已经有了答案: What registers are preserved through a linux x86-64 function call (3 个答案) 关闭 4 年前。 这
在下面的 C++ 源程序集中。为什么将 RAX 插入堆栈? RAX,据我所知,ABI 可以包含来自调用函数的任何内容。但是我们将它保存在这里,然后将堆栈向后移动 8 个字节。所以堆栈上的 RAX 是,
我可以写 mov rax, 1(7 字节编码 48, C7, C0, 01, 00, 00, 00),而不是写 mov eax, 1 (5字节编码B8,01,00,00,00)依赖自动高位双字归零。
我正在 gdb session 中分析事后崩溃。我正在查看函数的反汇编输出,我看到了: => 0x00007f8d354aed52 : callq *(%rax) => 表示这是崩溃时调用的指
在 x64 上,从 64 位绝对地址加载(即取消引用 64 位立即数)可以通过 movabs addr64, %rax 但是,当目标寄存器不是 rax 时汇编程序给出了一条错误消息,说 operand
这个问题已经有答案了: What do the E and R prefixes stand for in the names of Intel 32-bit and 64-bit registers
我可以使用 syscall for write 将内存中的一些数据打印到 STDOUT: ssize_t write(int fd, const void *buf, size_t count); 即
#include #include typedef struct item { int low; int high; char label[16]; } Item; typedef str
这是一个将字符串作为输入传递的程序。 我对下面显示的汇编代码感到困惑,特别是第 6 行。这是我从研究中了解到的: rbp-48 是一个指针,指向存放argv 的栈地址。 (argv本身,是指向argv
我知道在 C 中调用 fork() 如果有错误会返回 -1,但我想知道当你调用 sys_fork 时错误返回值是什么> 在组装中。 我可能通常假设它也返回 -1 但我已经处理过 sys_brk 并且汇
我想知道是否有任何指令序列而不使用任何其他寄存器来将 RAX 的低 32 位复制到其高 32 位。当然,我也希望 EAX 完好无损。 最好也不使用任何堆栈内存。 最佳答案 我的尝试...在演示派对上进
我是一名优秀的程序员,十分优秀!