我正在尝试AAAA使用c 进行打印__asm__,如下所示:
#include <stdio.h>
int main()
{
__asm__("sub $0x150, %rsp\n\t"
"mov $0x0,%rax\n\t"
"lea -0x140(%rbp), %rax\n\t"
"movl $0x41414141,(%rax)\n\t"
"movb $0x0, 0x4(%rax)\n\t"
"lea -0x140(%rbp), %rax\n\t"
"mov %rax, %rdi\n\t"
"call printf\n\t");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
拆卸:
Dump of assembler code for function main:
0x0000000000400536 <+0>: push %rbp
0x0000000000400537 <+1>: mov %rsp,%rbp
0x000000000040053a <+4>: sub $0x150,%rsp
0x0000000000400541 <+11>: mov $0x0,%rax
0x0000000000400548 <+18>: lea -0x140(%rbp),%rax
0x000000000040054f <+25>: movl $0x41414141,(%rax)
0x0000000000400555 <+31>: movb $0x0,0x4(%rax)
0x0000000000400559 <+35>: lea -0x140(%rbp),%rax
0x0000000000400560 <+42>: mov %rax,%rdi
0x0000000000400563 <+45>: callq 0x400410 <printf@plt>
0x0000000000400568 <+50>: mov $0x0,%eax
0x000000000040056d <+55>: pop %rbp
0x000000000040056e <+56>: retq
End of assembler dump.
Run Code Online (Sandbox Code Playgroud)
在运行代码时,基本上有两个问题。#1,它不打印“ AAAA”,#1,当RIP到达时retq,它会抛出segmentation fault
有什么我想念的吗?
您的代码存在以下问题:
您的代码的主要问题是,调用后,您无法将堆栈指针恢复为其先前的值printf。编译器不知道您修改了堆栈指针,并尝试返回到at处的任何地址(%rsp),从而使程序崩溃。要解决此问题,请恢复rsp到asm语句开头的值。
您忘记设置al0来表示没有浮点值传递给printf。这是printf一个可变参数函数。al将值设置得太高(所有值都小于或等于0)不会引起任何问题,但al正确设置仍然是一种好习惯。要解决此问题,请al在调用之前将其设置为0 printf。
就是说,您不能安全地假定编译器将设置基本指针。要解决此问题,请确保仅引用rsp而不是引用,rbp或使用扩展asm使编译器可以解决此问题。
注意不要覆盖堆栈。请注意,下面的128个字节rsp称为红色区域,也必须保留。这在您的代码中很好,因为您分配了足够的堆栈空间来避免此问题。
您的代码默认假定在输入asm语句时,堆栈与16字节的倍数对齐。这也是您无法做出的假设。要解决此问题,请在调用之前将堆栈指针与16个字节的倍数对齐printf。
您覆盖了一堆寄存器;除rax和之外rdi,对的调用printf可能会覆盖任何保存在调用者中的寄存器。编译器不知道您是否这样做,并可能假定所有寄存器都保留了以前的值。要解决此问题,请声明一个适当的清单列表,或者保存并还原您计划覆盖的所有寄存器,包括所有保存了调用者的寄存器。
TL; DR:不要从内联汇编中调用函数,也不要将内联汇编用作学习工具!很难做到正确,并且不会教给您关于汇编编程的任何有用信息。
这是我将如何在常规汇编中编写代码的方法。我建议您这样做:
.section .rodata # enter the read-only data section
str: .string "AAAA" # and place the string we want to print there
.section .text # enter the text section
.global main # make main visible to the link editor
main: push %rbp # establish...
mov %rsp, %rbp # ...a stack frame (and align rsp to 16 bytes)
lea str(%rip), %rdi # load the effective address of str to rdi
xor %al, %al # tell printf we have no floating point args
call printf # call printf(str)
leave # tear down the stack frame
ret # return
Run Code Online (Sandbox Code Playgroud)
这是内联汇编中如何调用函数的方法。了解您永远都不要这样做。甚至不是出于教育目的。这样做太可怕了。如果要使用C调用函数,请使用C代码而不是内联汇编进行。
也就是说,您可以执行以下操作。请注意,我们使用扩展程序集使生活变得更加轻松:
int main(void)
{
char fpargs = 0; /* dummy variable: no fp arguments */
const char *str = "AAAA";/* the string we want to print */
__asm__ volatile ( /* volatile means we do more than just
returning a result and ban the compiler
from optimising our asm statement away */
"mov %%rsp, %%rbx;" /* save the stack pointer */
"and $~0xf, %%rsp;" /* align stack to 16 bytes */
"sub $128, %%rsp;" /* skip red zone */
"call printf;" /* do the actual function call */
"mov %%rbx, %%rsp" /* restore the stack pointer */
: /* (pseudo) output operands: */
"+a"(fpargs), /* al must be 0 (no FP arguments) */
"+D"(str) /* rdi contains pointer to string "AAAA" */
: /* input operands: none */
: /* clobber list */
"rsi", "rdx", /* all other registers... */
"rcx", "r8", "r9", /* ...the function printf... */
"r10", "r11", /* ...is allowed to overwrite */
"rbx", /* and rbx which we use for scratch space */
"cc", /* and flags */
"memory"); /* and arbitrary memory regions */
return (0); /* wrap this up */
}
Run Code Online (Sandbox Code Playgroud)