堆栈和vtable [重新]位置

时间:2011-02-05 15:39:53

标签: c++ assembly g++ x86-64 inline-assembly

注意:要了解我的问题,可能需要了解我的项目和问题。如果没有,请直接跳到"问题"底部的部分。

<小时/>的 PROJECT

我正在编写一个C ++类,通过使用Pause()和Resume()使其父级能够像同步/阻塞线程一样工作。

这是一个如何运作的例子。

class BlockingThread
   : public BlockingThreadBase // all the Asm magic happens in BlockingThreadBase
{
  void StartStopHere(void) // called upon the first Resume() call (pure virtual in base)
  {
    printf("1"); Pause();
    printf("3"); Pause();
    printf("5"); Pause();
  }
};

int main(void)
{
  BlockingThread obj;

  obj.Resume(); printf("2");
  obj.Resume(); printf("4");
  obj.Resume(); printf("6");

  return 0;
}

// OUTPUT: 123456

我尝试过真正的线程和一些新颖的想法但是它们在代码位置之间传输的速度太慢了,每秒 2100万次。

我最近的想法是使用堆栈(堆栈缓冲区)来创建多个堆栈的错觉。调用obj1.Resume()时,它将返回其个人堆栈的位置New #1 Stack,执行直到Pause(),然后返回到它所在的上一个堆栈位置。

<小时/>的画集

如果没有main()中的任何BlockingThread个对象,堆栈的外观如何。

 _________________
| Normal | Stack  |
| Stack  | Buffer |
|________|________|

main()中的BlockingThread对象如何在堆栈中显示。

 ___________________________________
| Normal | Stack  | New #1 | Stack  |
| Stack  | Buffer | Stack  | Buffer |
|________|________|________|________|

main()中的两个 BlockingThread对象在堆栈中的外观如何。

 _____________________________________________________
| Normal | Stack  | New #1 | Stack  | New #2 | Stack  |
| Stack  | Buffer | Stack  | Buffer | Stack  | Buffer |
|________|________|________|________|________|________|

<小时/>的问题

当转移到&#34;新&#34;堆栈,然后调用obj.Resume()(来自main),然后调用StartStopHere()会在调用StartStopHere()时产生段错误。当我尝试从BlockingThreadBase获取成员变量的值时,GDB说can't find linker symbol for virtual table for 'BlockingThreadBase' value。这就是为什么我怀疑它在调用StartStopHere()的位置时遇到同样的问题。

<小时/>的问题

(如果您没有阅读其他部分,请忽略斜体字)

如何找到[并移动或复制] [正常<中的类的vtable(或其位置,如果存储了什么) / em>] stack [到一个新的堆栈]?

2 个答案:

答案 0 :(得分:1)

我认为您正在寻找的是合作线程。要快速简单地实现它,请查看libco。 http://byuu.org/files/libco_v16.tar.bz2。 coswitching在原始程序集中实现,适用于x86,x86_64,PPC32和PPC64。它还有使用setjmp / longjmp和posix ucontext(非常慢)的实现(ab)。 这种堆栈混合的开销大约是5倍。 2000万互换/秒应该可以正常工作。测试速度包括一些测试程序。

示例:

#include "libco.h"
#include <stdio.h>

static cothread_t t1;
static cothread_t t2;

static void foo(void)
{
   for (int i = 1; i < 10; i+=2)
   {
      printf("%d\n", i);
      co_switch(t1); // Swap back to main cothread
   }
}

int main(void)
{
   // Get a handle to the current coinstance.
   t1 = co_active();

   t2 = co_create(10000, foo); // New cothread with stacksize 10000.

   for (int i = 0; i < 10; i+=2)
   {
      printf("%d\n", i);
      co_switch(t2); // Swap to cothread t2.
   }

   co_delete(t2);
}

答案 1 :(得分:1)

我认为你的项目的魔力是通过一些装配魔法发生的。这显然意味着这将是特定于体系结构的。要检查如何从汇编中访问vtable(或vpointer)到类,最好只是检查copiler在访问虚拟方法时如何做到这一点 - 简单地解除代码并查看。 在我测试的x86 linux g ++复制程序中 - 对象的前四个字节是指向虚拟函数的表(我认为静态分配)的指针。

我认为没有任何方法可以独立进行体系结构,因为不同的体系结构可能会使用不同的方法来实现vtable。因此,我不希望c ++有任何手段。

你的问题太多了。但是,我认为,如果简单的memcpy(&amp; BlockingThread,sizeof(BlockingThread))不起作用,那么你将无法复制更多内容。