Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/61.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 什么是蹦床功能?_C_Language Agnostic_Programming Languages_Trampolines - Fatal编程技术网

C 什么是蹦床功能?

C 什么是蹦床功能?,c,language-agnostic,programming-languages,trampolines,C,Language Agnostic,Programming Languages,Trampolines,在最近的工作讨论中,有人提到蹦床功能 我已经阅读了网站上的描述。这足以给出功能的总体概念,但我希望更具体一点 你有一段简单的代码来演示蹦床吗?我将给你一个例子,我在一个在线游戏的反作弊补丁中使用了这个例子 我需要能够扫描游戏加载的所有文件进行修改。因此,我发现最有效的方法是在CreateFileA中使用蹦床。因此,当游戏启动时,我会使用GetProcAddress找到CreateFileA的地址,然后修改函数的前几个字节,插入汇编代码,跳转到我自己的“trampoline”函数,在那里我会做一些

在最近的工作讨论中,有人提到蹦床功能

我已经阅读了网站上的描述。这足以给出功能的总体概念,但我希望更具体一点


你有一段简单的代码来演示蹦床吗?

我将给你一个例子,我在一个在线游戏的反作弊补丁中使用了这个例子

我需要能够扫描游戏加载的所有文件进行修改。因此,我发现最有效的方法是在CreateFileA中使用蹦床。因此,当游戏启动时,我会使用GetProcAddress找到CreateFileA的地址,然后修改函数的前几个字节,插入汇编代码,跳转到我自己的“trampoline”函数,在那里我会做一些事情,然后在我的jmp代码之后跳回CreateFile中的下一个位置。要能够可靠地完成这项工作,还需要一点技巧,但基本概念只是挂接一个函数,强制它重定向到另一个函数,然后跳回原始函数


编辑:微软有这样一个框架,你可以看看。调用

以下是嵌套函数的示例:

#include <stdlib.h>
#include <string.h>
/* sort an array, starting at address `base`,
 * containing `nmemb` members, separated by `size`,
 * comparing on the first `nbytes` only. */
void sort_bytes(void *base,  size_t nmemb, size_t size, size_t nbytes) {
    int compar(const void *a, const void *b) {
        return memcmp(a, b, nbytes);
    }
    qsort(base, nmemb, size, compar);
}
#包括
#包括
/*对数组排序,从地址'base'开始,
*包含'nmemb'成员,由'size'分隔,
*仅在第一个'n字节'上进行比较*/
空排序字节(空*基、大小nmemb、大小大小、大小N字节){
整数比较(常数无效*a,常数无效*b){
返回memcmp(a,b,n字节);
}
qsort(base、nmemb、size、compar);
}
compar
不能是一个外部函数,因为它使用的是
nbytes
,它只在
sort_bytes
调用期间存在。在某些体系结构上,在运行时生成一个小存根函数--trampoline,它包含当前调用
sort\u bytes
的堆栈位置。调用时,它跳转到
compar
代码,传递该地址


在PowerPC这样的体系结构上不需要这种混乱,ABI指定函数指针实际上是一个“胖指针”,一个包含指向可执行代码的指针和另一个指向数据的指针的结构。然而,在x86上,函数指针只是一个指针。

还有维基百科上描述的LISP意义上的“蹦床”:

在某些LISP实现中使用 蹦床是一个循环,反复地 调用thunk返回函数。A. 一张蹦床就足够了 表示一个对象的所有控制传输 程序;这样表达的程序是 蹦床式或“蹦床式”; 将程序转换为蹦床 风格是蹦床。蹦床 函数可以用来实现 中的尾部递归函数调用 面向堆栈的语言

假设我们正在使用Javascript,并希望以延续传递样式编写朴素的Fibonacci函数。我们这样做的原因与此无关——例如,与JS的端口方案无关,或者与我们无论如何都必须使用的CPS一起调用服务器端函数

因此,第一次尝试是

function fibcps(n, c) {
    if (n <= 1) {
        c(n);
    } else {
        fibcps(n - 1, function (x) {
            fibcps(n - 2, function (y) {
                c(x + y)
            })
        });
    }
}

对于C,蹦床是一个函数指针:

size_t (*trampoline_example)(const char *, const char *);
trampoline_example= strcspn;
size_t result_1= trampoline_example("xyzbxz", "abc");

trampoline_example= strspn;
size_t result_2= trampoline_example("xyzbxz", "abc");

编辑:更深奥的蹦床将由编译器隐式生成。其中一个用途就是跳转表。(尽管在你开始尝试生成复杂代码的越远的地方,显然有更复杂的方法。)

我目前正在试验为方案解释器实现尾部调用优化的方法,因此目前我正在尝试弄清楚蹦床对我来说是否可行

据我所知,它基本上只是由蹦床函数执行的一系列函数调用。每个函数都被称为thunk,并返回计算中的下一步,直到程序终止(空继续)

以下是我为提高对蹦床的理解而编写的第一段代码:

#include <stdio.h>

typedef void *(*CONTINUATION)(int);

void trampoline(CONTINUATION cont)
{
  int counter = 0;
  CONTINUATION currentCont = cont;
  while (currentCont != NULL) {
    currentCont = (CONTINUATION) currentCont(counter);
    counter++;
  }
  printf("got off the trampoline - happy happy joy joy !\n");
}

void *thunk3(int param)
{
  printf("*boing* last thunk\n");
  return NULL;
}

void *thunk2(int param)
{
  printf("*boing* thunk 2\n");
  return thunk3;
}

void *thunk1(int param)
{
  printf("*boing* thunk 1\n");
  return thunk2;
}

int main(int argc, char **argv)
{
  trampoline(thunk1);
}
using System.Collections.Generic;
using System.Linq;

class Game
{
    internal static int RollMany(params int[] rs) 
    {
        return Trampoline(1, 0, rs.ToList());

        int Trampoline(int frame, int rsf, IEnumerable<int> rs) =>
              frame == 11             ? rsf
            : rs.Count() == 0         ? rsf
            : rs.First() == 10        ? Trampoline(frame + 1, rsf + rs.Take(3).Sum(), rs.Skip(1))
            : rs.Take(2).Sum() == 10  ? Trampoline(frame + 1, rsf + rs.Take(3).Sum(), rs.Skip(2))
            :                           Trampoline(frame + 1, rsf + rs.Take(2).Sum(), rs.Skip(2));
    }
}

让我用不同的语言为使用蹦床实现的阶乘函数添加几个示例:

斯卡拉:

密封特性反弹[A]
案例类完成[A](结果:A)扩展反弹[A]
case类调用[A](thunk:()=>Bounce[A])扩展Bounce[A]
def蹦床[A](弹跳:弹跳[A]):A=弹跳比赛{
案例调用(thunk)=>蹦床(thunk())
案例完成(x)=>x
}
def阶乘(n:Int,乘积:BigInt):反弹[BigInt]={
if(n阶乘(n-1,n*乘积))
}
对象阶乘扩展应用程序{
println(蹦床(因子(100000,1)))
}
爪哇:

import java.math.biginger;
职业蹦床
{
public T get(){return null;}
公共蹦床运行(){return null;}
T execute(){
蹦床蹦床=这个;
while(trampoline.get()==null){
蹦床=蹦床跑();
}
返回蹦床;
}
}
公共类阶乘
{
公共静态蹦床阶乘(最终整数n,最终双整数乘积)
{
如果(n回调!=NULL)
数据->回调(数据);
}
//-----------------------------------------
typedef结构\u因子参数{
int n;
int产品;
}因子参数;
空因子(蹦床数据*数据){
factorialParameters*参数=(factorialParameters*)数据->参数;
如果(参数->n回调=NULL;
}
否则{
参数->产品*=参数->n;
参数->n--;
}
}
int main(){
阶乘参数params={5,1};
蹦床_数据t={&factorial,¶ms};
蹦床;
printf(“\n%d\n”,参数产品);
返回0;
}
既然C#有了,就可以用蹦床优雅地解决问题了:

#include <stdio.h>

typedef void *(*CONTINUATION)(int);

void trampoline(CONTINUATION cont)
{
  int counter = 0;
  CONTINUATION currentCont = cont;
  while (currentCont != NULL) {
    currentCont = (CONTINUATION) currentCont(counter);
    counter++;
  }
  printf("got off the trampoline - happy happy joy joy !\n");
}

void *thunk3(int param)
{
  printf("*boing* last thunk\n");
  return NULL;
}

void *thunk2(int param)
{
  printf("*boing* thunk 2\n");
  return thunk3;
}

void *thunk1(int param)
{
  printf("*boing* thunk 1\n");
  return thunk2;
}

int main(int argc, char **argv)
{
  trampoline(thunk1);
}
using System.Collections.Generic;
using System.Linq;

class Game
{
    internal static int RollMany(params int[] rs) 
    {
        return Trampoline(1, 0, rs.ToList());

        int Trampoline(int frame, int rsf, IEnumerable<int> rs) =>
              frame == 11             ? rsf
            : rs.Count() == 0         ? rsf
            : rs.First() == 10        ? Trampoline(frame + 1, rsf + rs.Take(3).Sum(), rs.Skip(1))
            : rs.Take(2).Sum() == 10  ? Trampoline(frame + 1, rsf + rs.Take(3).Sum(), rs.Skip(2))
            :                           Trampoline(frame + 1, rsf + rs.Take(2).Sum(), rs.Skip(2));
    }
}
使用System.Collections.Generic;
使用System.Linq;
班级游戏
{
内部静态int RollMany(参数int[]rs)
{
返回蹦床(1,0,rs.ToList());
int蹦床(int帧、int rsf、IEnumerable rs)=>
帧==11
using System.Collections.Generic;
using System.Linq;

class Game
{
    internal static int RollMany(params int[] rs) 
    {
        return Trampoline(1, 0, rs.ToList());

        int Trampoline(int frame, int rsf, IEnumerable<int> rs) =>
              frame == 11             ? rsf
            : rs.Count() == 0         ? rsf
            : rs.First() == 10        ? Trampoline(frame + 1, rsf + rs.Take(3).Sum(), rs.Skip(1))
            : rs.Take(2).Sum() == 10  ? Trampoline(frame + 1, rsf + rs.Take(3).Sum(), rs.Skip(2))
            :                           Trampoline(frame + 1, rsf + rs.Take(2).Sum(), rs.Skip(2));
    }
}