Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/asp.net-mvc-3/4.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
如何在JavaScript(EnScript)中重写C++ MalOC/FLUE?_C++_Emscripten - Fatal编程技术网

如何在JavaScript(EnScript)中重写C++ MalOC/FLUE?

如何在JavaScript(EnScript)中重写C++ MalOC/FLUE?,c++,emscripten,C++,Emscripten,我重写了Module.\u malloc和Module.\u在Javascriptemscripten中释放,方法是包装原始函数并添加Console.log以显示内存地址、大小和分配的内存总量 我发现新函数只捕获了javascript调用到Mult..MaLoC和Mule.Field,并且它没有捕获到Maloc和免费的C++级别调用。我想知道为什么 根据Ofria先生的回答,Module.\u malloc和Module.\u free是c++的malloc和free的转换等价代码 我正在使用e

我重写了Module.\u malloc和Module.\u在Javascriptemscripten中释放,方法是包装原始函数并添加Console.log以显示内存地址、大小和分配的内存总量

我发现新函数只捕获了javascript调用到Mult..MaLoC和Mule.Field,并且它没有捕获到Maloc和免费的C++级别调用。我想知道为什么

根据Ofria先生的回答,Module.\u malloc和Module.\u free是c++的malloc和free的转换等价代码

我正在使用emscripten 1.35.0

编辑:下面是我如何用javascript包装函数的

var _defaultMalloc = Module._malloc;
var _defaultFree = Module._free;

var _totalMemoryUsed = 0;
var _mallocTracker = {};
Module._malloc = function(size) {
   _totalMemoryUsed += size;
   var ptr = _defaultMalloc(size)
   _mallocTracker[ptr] = size;

   console.log("MALLOC'd @" + ptr + " " + size + " bytes -- TOTAL USED " + _totalMemoryUsed + " bytes");
   return ptr;
}

Module._free = function(ptr) {
   var size = _mallocTracker[ptr];
   _totalMemoryUsed -= size;

   console.log("FREE'd @" + ptr + " " + size + " bytes -- TOTAL USED " + _totalMemoryUsed + " bytes");
   return _defaultFree(ptr);
}

简短的回答:您试图包装MalC/FILE的方法不起作用,因为公开Emscripten的MALOC/FULL实现的模块对象不是由本地C++代码调用的入口点。然而,通过一点黑客技术,你可以找到追踪这些电话的方法

为什么覆盖无效 <>我想你的答案可能会更好地表达:C++ C++的MALLC和免费调用的仿真在模块中公开。 注意:在这个答案的剩余部分,我通常只讨论malloc,但基本上适用于malloc的所有内容也适用于free

关于Emscripten如何处理malloc的所有血淋淋的细节,我将留待以后讨论,但简单地说:

使用标准设置,EnScript将C++程序编译为A.Out.js.< 此文件的一大块创建了一个asm对象。这包含所有转换的C++代码,例如,C++、McLo.

的主要库函数和JavaScript版本的JavaScript实现。 <> > ASM内转换的C++代码在ASM .</P>内直接引用内部库函数。 <> >引用C++函数和许多库函数,特别是主函数、MyOLC和无空函数作为ASM对象的属性公开。它们还作为模块对象的属性公开,并作为独立变量存在

这样,原始C++代码只调用在ASM代码块中定义的MyOLLC的内部实现。Emscripten框架的其余部分以及任何其他JavaScript代码也可以通过任何公开的引用调用此函数:_malloc、Module._malloc或Module['''u malloc']和asm._malloc或asm[''u malloc']

因此,如果使用包装版本替换任何或所有_malloc、Module._malloc或asm._malloc,这将只影响从Emscripten框架的其余部分或其他JavaScript代码进行的调用。它不会影响转换的C++代码调用。 跟踪调用_malloc/_free的方法 1.官方途径 在我们进入一些低级黑客之前,我应该提到Emscripten内置了一个跟踪API,根据他们的帮助页面,它提供了一些有用的功能,可以更好地查看应用程序内部的情况,特别是内存使用情况

我没有尝试过使用它,但对于严肃的调试工作来说,这可能是最好的选择。但是,您需要设置一个单独的进程来接收来自被测应用程序的跟踪消息,因此在某些情况下,这可能会有些过分

如果你想继续这样做,官方文档和描述了一家公司是如何利用跟踪API的,我与他们没有任何关系:那一页刚刚出现在搜索结果中

2.破解它

上面提到的问题是,转换后的C++调用所调用的是ASM对象内部的函数,因此不受外部层创建的任何包装器的影响。经过一些调查,我想出了两种克服这个问题的方法。由于两者都有点老套,纯粹主义者可能想把目光移开

首先,让我们从一小段代码开始,作为我们的测试平台,根据页面上的内容进行调整:

你好,c

现在,我们将创建以下JavaScript文件来包装malloc并释放:

tracemaloc.js

在Emscripten框架中有两个对_malloc的调用,但我们感兴趣的调用——来自C代码的调用——还没有被跟踪

2a。一次性黑客 如果我们检查a.out.js文件,我们将发现以下代码段,这是转换为JavaScript的C代码的开始:

function _main() {
 var $0 = 0, $1 = 0, $2 = 0, $3 = 0, $4 = 0, $fred = 0, $vararg_buffer = 0, label = 0, sp = 0;
 sp = STACKTOP;
 STACKTOP = STACKTOP + 16|0; if ((STACKTOP|0) >= (STACK_MAX|0)) abort();
 $vararg_buffer = sp;
 $0 = 0;
 $1 = (_malloc(1234321)|0);
问题是对_malloc的调用引用了内部函数,而不是我们重写的函数。为了解决这个问题,我们可以编辑a.out.js,在_main的顶部添加以下两行:

这将使用asm对象持有的公共版本的引用替换内部属性_malloc和_free,到目前为止,这些公共版本已被我们的包装版本替换。虽然这看起来有点像循环,但它可以工作,因为包装版本已经存储了对真实malloc函数的引用,所以 你仍然这么叫,而不是我们刚刚覆盖的引用

如果现在重新运行a.out.js文件而不重建:

C:\Program Files\Emscripten\Test>node a.out.js
Wrapping malloc/free
_malloc( 42 )
<--- 5251080
_malloc( 5 )
<--- 5251128
_malloc( 1234321 )
<--- 5251144
Hello, world!
_free( 5251144 )
<--- undefined
在我的副本中,第一个更改位于第680行,第二个更改位于第964行。第一个更改告诉框架从asm对象导出函数wrapAllocFree;第二个更改定义了将要导出的函数。可以看出,这只是执行了我们在第2a节中手动编辑的两行代码,以及一个完全可选的跟踪行,以显示激活已经发生

为了利用这一变化,我们还需要在traceMalloc.js中取消对新函数调用的注释,使其内容如下:

        return result ;
      }
      // Hack 2b: invoke semi-permanent code added to emscripten.py
      asm.wrapMallocFree();        }
  }
}
现在,我们可以重新构建和运行代码,并查看跟踪的所有调用,而无需手动编辑a.out.js:

对象asm是使用定义的。本质上,整个块定义了一个立即执行的匿名函数。执行该函数的结果就是分配给对象asm的结果。此执行在遇到上述代码时发生。IIFE的要点是,该匿名函数中定义的变量/函数仅对该函数中的代码可见。外部世界看到的只是该函数返回的分配给asm的内容

我们感兴趣的是,我们看到了_main转换的C代码和_mallocemscripten的内存分配器实现的定义。由于JavaScript/IIFE的工作方式,当在_main中执行代码时,它对_malloc的调用将始终引用这个内部版本的_malloc

IIFE的返回值是一个具有多个属性的对象。这个对象的属性名恰好与匿名函数中的对象/函数名相同。虽然这可能会让人感到困惑,但不涉及任何歧义。分配给asm的返回对象有一个名为_malloc的属性。该属性的值设置为等于内部对象的值\u malloc函数的定义实质上创建了一个属性/对象,该属性/对象引用了作为函数体的代码块。此引用可以像所有其他引用一样进行操作

模块的定义 施工后不久,我们有以下代码块:

var _free = Module["_free"] = asm["_free"];
var _main = Module["_main"] = asm["_main"];
var _i64Add = Module["_i64Add"] = asm["_i64Add"];
var _memset = Module["_memset"] = asm["_memset"];
var runPostSets = Module["runPostSets"] = asm["runPostSets"];
var _malloc = Module["_malloc"] = asm["_malloc"];
对于新创建的asm对象的选定属性,这有两件事:a它在第二个对象模块中创建属性,该属性引用与asm属性相同的内容;b它创建一些全局变量,这些变量也引用这些属性。全局变量供Emscripten框架的其他部分使用;模块对象供可能添加到Emscripten生成的代码中的其他JavaScript代码使用

所有的路都通向马洛克 在这一点上,我们有以下几点:

在用于创建asm的匿名函数中定义了一段代码,它提供了Emscripten对C/C++的_malloc函数的实现/仿真。这段代码是真正的malloc。应该注意的是,该代码或多或少独立于引用它的任何对象/属性

IIFE有一个名为_malloc的内部对象,当前引用上述代码。原始C/C++代码对malloc的调用将使用此对象的值进行

对象asm有一个名为_malloc的属性,该属性当前也引用上述代码块

对象模块还有一个名为_malloc的属性,该属性当前引用上述代码块

有一个全局对象\u malloc。毫不奇怪,它还引用了上述代码块

此时,在用于构建asm的IIFE中使用_mallocglobal scope,Module._malloc或Module['''u malloc'],asm._malloc或_malloc都将在同一代码块中结束–malloc的真正实现

在函数上下文中执行以下代码片段时:


只有这样,IIFE内部对象才会改变。执行时,它是新值asm.\u malloc正在引用我们的包装函数。此时,对malloc引用的所有四个变体都指向我们的包装器函数。该函数仍然可以通过变量real_malloc访问malloc的实际实现,因此现在,每当代码的任何部分调用malloc时,该调用都会通过我们的包装函数,以便跟踪调用。

您是如何重写和包装该函数的?请提供您在代码中的具体操作。@Bumsikim感谢您的回复。我添加了代码。@德格我已经更新了我的答案,对引擎盖下发生的事情进行了正确的解释,并用了几种方法来追踪C++调用到Maloc。
function _main() {
 var $0 = 0, $1 = 0, $2 = 0, $3 = 0, $4 = 0, $fred = 0, $vararg_buffer = 0, label = 0, sp = 0;
 sp = STACKTOP;
 STACKTOP = STACKTOP + 16|0; if ((STACKTOP|0) >= (STACK_MAX|0)) abort();
 $vararg_buffer = sp;
 $0 = 0;
 $1 = (_malloc(1234321)|0);
function _main() {
 _malloc = asm._malloc;
 _free = asm._free;
C:\Program Files\Emscripten\Test>node a.out.js
Wrapping malloc/free
_malloc( 42 )
<--- 5251080
_malloc( 5 )
<--- 5251128
_malloc( 1234321 )
<--- 5251144
Hello, world!
_free( 5251144 )
<--- undefined
C:\Program Files\Emscripten\emscripten\1.35.0>fc emscripten.py.original emscripten.py
Comparing files emscripten.py.original and EMSCRIPTEN.PY
***** emscripten.py.original
    exports = []
    for export in all_exported:
***** EMSCRIPTEN.PY
    exports = []
    all_exported.append('wrapMallocFree')                 <--- Add this line
    for export in all_exported:
*****

***** emscripten.py.original
// EMSCRIPTEN_START_FUNCS
function stackAlloc(size) {
***** EMSCRIPTEN.PY
// EMSCRIPTEN_START_FUNCS
function wrapMallocFree() {                              <--- Add these lines
  console.log( 'wrapMallocFree()' ) ;                    <--- Add these lines
  _malloc = asm._malloc ;                                <--- Add these lines
  _free = asm._free ;                                    <--- Add these lines
}                                                        <--- Add these lines
function stackAlloc(size) {
*****
        return result ;
      }
      // Hack 2b: invoke semi-permanent code added to emscripten.py
      asm.wrapMallocFree();        }
  }
}
C:\Program Files\Emscripten\Test>emcc --pre-js traceMalloc.js hello.c

C:\Program Files\Emscripten\Test>node a.out.js
Wrapping malloc/free
wrapMallocFree()
_malloc( 42 )
<--- 5251080
_malloc( 5 )
<--- 5251128
_malloc( 1234321 )
<--- 5251144
Hello, world!
_free( 5251144 )
<--- undefined
// EMSCRIPTEN_START_ASM
var asm = (function(global, env, buffer) {

   ...

   function _main() {
      ...
      $1 = (_malloc(1234321)|0);
      ...
   }

   ...

   function _malloc($bytes) {
      ...
      return ($mem$0|0);
   }

   ...

   return { ... _malloc: _malloc, ... };
})
// EMSCRIPTEN_END_ASM
(Module.asmGlobalArg, Module.asmLibraryArg, buffer);
var _free = Module["_free"] = asm["_free"];
var _main = Module["_main"] = asm["_main"];
var _i64Add = Module["_i64Add"] = asm["_i64Add"];
var _memset = Module["_memset"] = asm["_memset"];
var runPostSets = Module["runPostSets"] = asm["runPostSets"];
var _malloc = Module["_malloc"] = asm["_malloc"];
      var real_malloc = _malloc ;
      Module['_malloc'] = asm['_malloc'] = _malloc = function( size ) {
        console.log( '_malloc( ' + size + ' )' ) ;
        var result = real_malloc.apply( null, arguments ) ;
        console.log( '<--- ' + result ) ;
        return result ;
      }
_malloc = asm._malloc ;