修改代码以在 f2 中使用 asm 打印 A 而不是 BA [关闭]

2024-03-14

#include <stdio.h>
void f2(){}//no code
void f1(){
    int b=3,c=7;
    c=b+c;
    f2();//f2 call
    printf("B\n");
}
int main (void) {
    int a=3;
    a=a+1;
    f1();//f1 call
    printf("A\n");
    return 0;
}

在 f2 函数中编写一段代码,该代码将改变上述 C 程序的控制。根据上面的代码,控制从 main 函数转到 f1 函数,f1 到 f2,然后再次从 f2 返回到 f1,再从 f1 返回到 main。但是,您只需要在函数 f2 中编写一些代码,这会将您的控制直接从 f2 移动到 main,这样输出将只出现“A”而不是“BA”。 F1 函数在执行过程中不能被多次调用。您不能修改 f1 和 main 函数。你不能写任何 printf 类型 f2 函数内的类似语句(在 C 或汇编中)。输出“A”应该仅从主函数中打印

我无法解决,也不知道该怎么做。


You could只需不返回即可安全且便携地做到这一点f1 (or main)。简单地做他们想做的事would完成后返回,然后退出:

void f2() {
    printf("A\n");
    exit(0);
}

不幸的是,这违反了“A必须仅由输出mainfunction”的要求,所以你必须有一些严肃的内部知识,并执行堆栈的操作(无论它是有风险和不可移植的)。

基本思想是分析状态would就在退出之前f1,并将代码放入f2将其设置为该状态。状态可能只是寄存器内容,但是may在某些情况下涉及更复杂的事情(例如,考虑在 C++ 中展开异常处理程序,或者可能由其余部分引起的任何全局影响)f1).

这样,当你退出时f2,返回点将位于main而不是f1. This could就像这样简单:

void f2() {
    asm "load sp <value>"
}

where <value>是你需要计算的值。注意asm上面的代码需要根据您的环境进行定制。由于您没有提供CPU架构(或其他具体细节),我使用了mythicalCPU上面带有一个load指令和sp登记。


为了进一步说明,假设您编译的代码为f2看起来像这样(x86-64,带有我添加的注释):

f2:     push    rbp                     # prolog stack frame set up.
        mov     rbp, rsp

        ## Point 1

        mov     rsp, rbp                # epilog.
        pop     rbp
        ret

and f1好像:

b_str:  .string "B\n"
f1:     push    rbp                     # prolog stack frame set up.
        mov     rbp, rsp
        sub     rsp, 16                 # allocate space for locals.

        mov     DWORD PTR [rbp-4], 3    # store values for b and c.
        mov     DWORD PTR [rbp-8], 7

        mov     eax, DWORD PTR [rbp-4]  # add b to c.
        add     DWORD PTR [rbp-8], eax

        mov     eax, 0                  # make call to f2().
        call    f2

        mov     edi, OFFSET FLAT:b_str  # output B.
        call    printf

        ## Point 2

        mov     rsp, rbp                # epilog.
        pop     rbp
        ret

你需要做的就是在点 1 处放置一些东西,这样它就会返回就像在第 2 点一样。在此代码中,可以通过添加一个值来实现rbp,正好足以退出:

  • 推送的返回值call f2; and
  • the push rbp开始时f2.

For example, if the call pushed a 32-bit return address and the push was for a 64-bit register, you would need to add twelve to rbp (64 bits = 8 bytes(a) and 32 bits = 4 bytes, giving 12).

我还没有进行深入的分析来确认这是添加的正确值,但它为您提供了基本的想法。

无论如何,它可能需要根据您的情况进行定制,因为它取决于编译器、调用约定、CPU 选择、优化级别以及可能的许多其他因素等因素。


(a) Using the "byte is eight bits" definition, though I normally prefer "octet" for that.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

修改代码以在 f2 中使用 asm 打印 A 而不是 BA [关闭] 的相关文章

随机推荐