【问题标题】:Running a function on a separately allocated stack在单独分配的堆栈上运行函数
【发布时间】:2012-08-01 03:57:29
【问题描述】:

我正在尝试在单独分配的堆栈上运行一个函数。

我想保留堆栈以供以后使用,以便我可以恢复它并恢复功能。

以下代码编译并运行,但屏幕上没有任何内容。

#include <cstdlib>
#include <csetjmp>
#include <iostream>
using namespace std;

unsigned char stack[65535];
unsigned char *base_ptr = stack + 65535 - 1;

unsigned char *old_stack;
unsigned char *old_base;

void function()
{
    cout << "hello world" << endl;
}

int main()
{
    __asm
    {
        mov old_base, ebp
        mov old_stack, esp

        mov ebp, base_ptr
        mov esp, base_ptr

        call function

        mov ebp, old_base
        mov esp, old_stack
    }
}

使用vs2012/win8/intel Q9650

【问题讨论】:

  • 也许setjmp/longjmp 可能对您的问题有用?
  • setjmp/longjmp 不保留堆栈,只保留 cpu 寄存器。所以如果你 longjmp 退出一个函数,本地的 vars 可以被覆盖。
  • 您没有告诉我们您使用的是哪个编译器。使用一个支持 MASM 样式的程序集,我会写 mov ebp,[base_ptr]mov esp,[base_ptr]
  • 不会 [base_ptr] 等同于 (*base_ptr) 吗?
  • @albundy - 这取决于汇编程序的语法。你必须表达&amp;base_ptrbase_ptr*base_ptr的等价物。你来这里的是哪一个?这取决于!要获得 C 风格 eax = *base_ptr;,您必须同时执行 mov eax,[base_ptr]mov eax,[eax]

标签: c++ assembly x86 stack


【解决方案1】:

实际上,我认为您的代码没有任何问题。 您的样本按原样编译、链接和运行。

也许您的控制台设置有问题,或者一些全局 STL/CRT 初始化或其他问题。无论如何,您可以在 function 中放置一个断点以确保您到达那里。

【讨论】:

  • 很奇怪........我刚刚将平台工具集从“Visual Studio 11 (v110)”更改为“Visual Studio 2010 (v100)”,现在它可以工作了 =/跨度>
  • @albundy 也许 VS11 不适合 64K 的堆栈。尝试 a) 增加堆栈大小; b) 使用优化编译; c) 使用 printf 代替 cout。
  • @Igor Skochinsky:正确的观点(尽管不适合显示字符串输出函数调用链的 64K 堆栈似乎很奇怪)。通常堆栈的顶部有一个不可访问的页面,因此它的访问会导致堆栈溢出或访问冲突异常。而超过这个自定义“堆栈”只会覆盖一些全局数据或类似的东西......
  • @valdo:iostreams 可能是标准 C++ 中最臃肿(而且,IMO,尴尬和无用)的部分。如果它能够运行超过 64KB,我一点也不会感到惊讶,尤其是在优化关闭的情况下。
【解决方案2】:

欢迎使用 C++ 并命名修改。 C++ 中的函数名称被编译器修改(这样使用 gcc 函数对我来说变成了 _Z8functionv)。这是为了方便函数重载。编译器会跟踪它在后台赋予不同函数的实际名称,因此您不会意识到这一点。对于任何其他尝试与 C++ 交互的语言来说,这都是一个问题。

此代码不会链接到我的计算机上。

解决方案: 1)用g++编译并传递-S标志(所以g++ -S test.cpp)。然后看一下汇编输出(cat test.s),看看调用了什么函数。然后将“调用函数”中的名称更改为“调用_Z8functionv”(对我来说 - 它对你来说很容易不同)。 2) 使用 C: 将 cout

我认为您并没有使用 gcc(因为汇编器是从头到尾处理气体 - 我不得不切换汇编器上的所有操作数)。

【讨论】:

  • 我在函数()中放了一个断点,它正在被调用。我什至可以单步执行 cout 代码 =/
  • 几乎你的代码:pastebin.com/JsFQSAsy,用 g++ 编译,然后运行,打印出“Hello World”。您使用的是什么环境(编译器/操作系统/机器)?
  • 和程序 "int main() {cout
  • 无法编译。 vs2012好像不支持asm(""),只支持__asm{}
  • 但是问题作者并没有抱怨链接器问题! IT 构建正常,但没有达到预期效果
【解决方案3】:

根据 Intel 针对 MOV 的 x86 文档第 3-403 页,您应该在加载新的 ESP 值之前立即加载 SS 寄存器。这会阻止任何中断运行,直到分配了 ESP

【讨论】:

  • 如果你要加载 both SS 和 ESP,那是为了同步。这里不会发生。
  • 这不是我阅读文档时的印象。我读它的意思是你必须在 ESP 之前设置 SS 以便在 ESP 未处于稳定状态时中断无法运行。设置 SS 会阻止所有中断运行,直到下一条指令执行完毕。
  • 如果您想同时更改 SS 和 ESP,您的解释是正确的。最初的 8086 没有此功能,因此在移动堆栈时存在竞争条件的风险。这里我们只用一条指令改变 ESP。那么就没有风险了,因为中断只能发生在指令之间,而不是在指令期间。
猜你喜欢
  • 2021-11-05
  • 1970-01-01
  • 2016-04-14
  • 2013-03-16
  • 2019-09-16
  • 1970-01-01
  • 1970-01-01
  • 2017-02-17
  • 1970-01-01
相关资源
最近更新 更多