c ++反汇编与逆向分析
![Image 1](https://i-blog.csdnimg.cn/blog_migrate/3046459ed4c435ccf60bad5179a49eb2.png)
I've been taking advantage of Web Assembly lately. It is supported by all the major browsers, allows one to make use of already existing useful code that has been written for other environments, and provides some performance benefits over JavaScript. Web Assembly has a lot of potential and support and I'd like to introduce other developers to it. I'm going to be using C++ in this post. But by no means is this the only language in which someone can make use of Web Assembly. In this post, I talk about why someone might want to consider web assembly and how to get a development environment setup.
最近,我一直在利用Web Assembly。 所有主要浏览器都支持它,它允许一个人使用为其他环境编写的已经存在的有用代码,并提供一些优于JavaScript的性能优势。 Web Assembly具有很大的潜力和支持,我想向其他开发人员介绍它。 在这篇文章中,我将使用C ++。 但这绝对不是有人可以使用Web Assembly的唯一语言。 在这篇文章中,我讨论了为什么有人可能想考虑Web组装以及如何进行开发环境设置。
什么是Web Assembly? (What is Web Assembly?)
Web Assembly is a specification for a virtual machine that runs in the browser. Compared to the highly dynamic JavaScript, Web Assembly can achieve much higher performance. Contrary to popular misconception though, Web Assembly doesn't completely replace JavaScript. You will probably use the two together. Web Assembly is based on LLVM (Low Level Virtual Machine), a stack based virtual machine that compilers can target. If someone wanted to make a new programming language, they could have the compiler for their language produce LLVM code and then use an already existing tool chain to compile it to platform specific code. A person building a compiler for a new language wouldn't need to make completely separate systems for different CPU architectures. Web Assembly being LLVM based could run code that was written by a variety of languages. Currently, there isn't support for garbage collection yet which restricts the languages that target it presently. C/C++, C#, and Rust are a few languages that can be used with Web Assembly presently with more expected in the future.
Web Assembly是在浏览器中运行的虚拟机的规范。 与高度动态JavaScript相比,Web Assembly可以实现更高的性能。 与流行的误解相反,Web Assembly并未完全替代JavaScript。 您可能会同时使用两者。 Web Assembly基于LLVM(低级虚拟机),LLVM是编译器可以定位的基于堆栈的虚拟机。 如果有人想制作一种新的编程语言,则可以让该语言的编译器生成LLVM代码,然后使用现有的工具链将其编译为平台特定的代码。 为新语言构建编译器的人不需要为不同的CPU体系结构制作完全独立的系统。 基于LLVM的Web程序集可以运行由多种语言编写的代码。 当前,尚不支持垃圾回收,这限制了目前针对垃圾回收的语言。 C / C ++,C#和Rust是目前可以与Web Assembly一起使用的几种语言,并且在将来会越来越多。
我可以使用哪些其他语言? (What Other Languages Can I Use?)
- C/C++ - I'll be using that language in this article C / C ++-我将在本文中使用该语言
- C#/.NET - I've got interest in this one and will write about it in the future. C#/。NET-我对此感兴趣,并将在以后进行介绍。
- Java Java
Rust - This is a newer language
Rust-这是一种较新的语言
为什么要使用Web Assembly? (Why Use Web Assembly?)
I suggest Web Assembly primarily for the performance benefits in computationally expensive operations. The binary format it uses is much more strict than JavaScript and it is more suitable for computationally intensive operations. There is also a lot of existing and tested code for work such as cryptography or video decoders that exist in C/C++ that one might want to use in a page. Despite all its flexibility, interpreted JavaScript code doesn't run as fast as a native binary. For some types of applications, this difference in performance isn't important (such as in a word processor). For other applications, differences in performance translate into differences in experiences.
我建议Web Assembly主要是为了在计算量大的操作中提高性能。 它使用的二进制格式比JavaScript严格得多,并且更适合于计算密集型操作。 还有很多现有的和经过测试的工作代码,例如人们可能希望在页面中使用的C / C ++中的加密或视频解码器。 尽管具有很大的灵活性,但是解释后JavaScript代码的运行速度不像本地二进制文件那样快。 对于某些类型的应用程序,这种性能差异并不重要(例如在文字处理器中)。 对于其他应用程序,性能差异会转化为体验差异。
While the demand for performance is a motivation to make a native binary, there are also security considerations. Native binaries may have access to more system resources than a web implemented solution. There may be more concern with ensuring that a program (especially if it is from a third party) doesn't do anything malicious or access resources without permission. Web Assembly helps bridge the gap between these two needs; it provides a higher performance execution environment within a sandbox.
虽然对性能的需求是制作本机二进制文件的动机,但也有安全方面的考虑。 本地二进制文件可能比Web实现的解决方案有权访问更多的系统资源。 确保程序(尤其是来自第三方的程序)不会进行任何恶意操作或未经许可访问资源可能会引起更多关注。 Web Assembly帮助弥合这两个需求之间的鸿沟; 它在沙箱中提供了更高性能的执行环境。
![WebAssemblySupport](https://i-blog.csdnimg.cn/blog_migrate/02b76893461c246ba98ca8ce1b7d893e.png)
C ++? 我不能因此导致缓冲区溢出吗? (C++? Can't I Cause a Buffer Overflow With That?)
Sure. But only within the confines of the sandbox in which the code will run. It could crash your program, but it can't cause arbitrary execution of code outside the sandbox. Also note that presently Web Assembly doesn't have any bindings to Host APIs. When you target Web Assembly, you don't have an environment that allows you to bypass the security restrictions in which JavaScript code will run. There's no direct access to the file system, there's no access to memory outside of your program, you will still be restricted to communicating with WebSockets and HTTP request that don't violate CORS restrictions.
当然。 但仅在运行代码的沙箱范围内。 它可能会使您的程序崩溃,但不会导致沙盒外部代码的任意执行。 还要注意,目前Web Assembly没有与Host API的任何绑定。 当您以Web程序集为目标时,您没有一个环境可以绕过JavaScript代码在其中运行的安全限制。 没有直接访问文件系统的权限,也没有访问程序外部内存的权限,您仍然会被限制与不违反CORS限制的WebSockets和HTTP请求进行通信。
如何设置开发人员环境 (How Do I Setup a Developer Environment)
There are different versions of instructions on the Internet for installing the Web Assembly tools. If you are running Windows 10, you may come across a set of instructions that start with telling you to install the Windows Subsystem for Linux. Don't use those instructions; I personally think they are unnecessarily complex. While I have the Windows Sub System for Linux installed and running for other purposes that's not where I like to compile my Web Assembly code.
Internet上有不同版本的说明,用于安装Web程序集工具。 如果您运行的是Windows 10,则可能会遇到一系列说明,这些说明从告诉您安装Linux的Windows子系统开始。 不要使用这些说明; 我个人认为它们不必要地复杂。 尽管我已经安装了Linux的Windows子系统并已将其运行用于其他目的,但这不是我希望编译Web Assembly代码的地方。
Using your operating system of choice (Windows 10/8/7, macOS, Linux) clone the Emscripten git repository, run a few scripts from it, and you are ready to go. Here are the commands to use. If you are on Windows, omit the ./
at the beginning of the commands.
使用您选择的操作系统(Windows 10/8/7,macOS,Linux)克隆Emscripten git存储库,从中运行一些脚本,即可开始使用。 这是要使用的命令。 如果您使用的是Windows,请在命令开头省略./
。
git https://github.com/emscripten-core/emsdk.git
cd emsdk
git pull
./emsdk install latest
./emsdk activate latest
With the tools installed, you will also want to set the some environment variables. There is a script for doing this. On Windows 10, run:
安装了工具后,您还需要设置一些环境变量。 有执行此操作的脚本。 在Windows 10上,运行:
emsdk_env.bat
For the other operating systems, run:
对于其他操作系统,运行:
source emsdk_env.sh
The updates that this makes to environment variables isn't persistent; it will need to be run again with the next reboot. For an editor, I suggest using Visual Studio Code. I'll be compiling from the command line in this article. Feel free to use the editor of your choice.
这对环境变量所做的更新不是持久性的。 它需要在下次重新启动时再次运行。 对于编辑器,我建议使用Visual Studio Code。 我将在本文的命令行中进行编译。 随意使用您选择的编辑器。
Web Assembly Explorer (Web Assembly Explorer)
I don't use it in this tool within this article, but Web Assembly Explorer is available as an online tool for compiling C++ into Web Assembly and is an option if you don't have the tools installed. https://mbebenita.github.io/WasmExplorer/
我不会在本文中的此工具中使用它,但是Web Assembly Explorer可以用作将C ++编译到Web Assembly中的在线工具,如果没有安装工具,则可以选择使用。 https://mbebenita.github.io/WasmExplorer/
你好,世界 (Hello World)
Now that we have the tools installed, we can compile and run something. We will do a hello world program. Type the following source code and save it in hello.cpp.
现在我们已经安装了工具,我们可以编译并运行某些东西。 我们将做一个你好世界程序。 输入以下源代码并将其保存在hello.cpp中 。
#include
int main(int argc, char**argv)
{
printf("Hello World!\n");
return 0;
}
To compile the code from the command line, type the following:
要从命令行编译代码,请键入以下内容:
emcc hello.cpp -o hello.html
After the compiler runs, you will have three new files:
编译器运行后,您将拥有三个新文件:
hello.wasm - the compiled version of your program
hello.wasm-程序的编译版本
hello.html - an HTML page for hosting your web assembly
hello.html-用于托管Web程序集HTML页面
hello.js - JavaScript for loading your web assembly into the page
hello.js-用于将Web程序集加载到页面中JavaScript
If you try to open the HTML file directly, your code probably will not run. Instead, the page will have to be served through an HTTP server. If you have node installed, use the node http-server
. You can install the http-server
with:
如果您尝试直接打开HTML文件,则您的代码可能无法运行。 而是必须通过HTTP服务器为该页面提供服务。 如果已安装节点,请使用节点http-server
。 您可以使用以下方法安装http-server
:
npm install http-server -g
Then, start the server from the directory with your hello.html:
然后,使用hello.html从目录启动服务器:
http-server . -p 81
Here, I've instructed the http-server
to run on port 81
. You can use the port of your choice here provided nothing else is using it. Remember to substitute the port that you chose throughout the rest of these instructions.
在这里,我已指示http-server
在端口81
上运行。 您可以在此处使用您选择的端口,前提是没有其他端口正在使用它。 记住,在其余所有说明中,请替换为您选择的端口。
Open a browser and navigate to http://localhost:81/hello.html. You'll see your code run. If you view the source for the page, there is a lot of "noise" in the file. Much of that noise is from the displayed images being embedded within the HTML. That's fine for playing around. But you will want to have something customized to your own needs.
打开浏览器并导航到http:// localhost:81 / hello.html 。 您将看到代码运行。 如果您查看页面的源代码,则文件中会有很多“噪音”。 大部分噪音来自嵌入HTML中的显示图像。 玩耍很好。 但是,您将需要根据自己的需求进行定制。
We can provide a shell or template file for the compiler to use. Emscripten has a minimal file available at https://github.com/emscripten-core/emscripten/blob/master/src/shell_minimal.html. Download that file. It will be used as our starting point. It is convenient for the sake of distribution for everything to be in one file. But I don't like the CSS and JavaScript being embedded within the file. The CSS here isn't needed and is being deleted. I'm moving the JavaScript to its own file and added a script references to it in my HTML. There are several items within the HTML and the script that are not necessarily needed. Let's look at the script first and start making this minimal file even more minimalist.
我们可以提供一个shell或模板文件供编译器使用。 Emscripten的最小文件位于https://github.com/emscripten-core/emscripten/blob/master/src/shell_minimal.html 。 下载该文件。 它将用作我们的起点。 为了将所有内容分发在一个文件中,这很方便。 但是我不喜欢将CSS和JavaScript嵌入文件中。 这里不需要CSS,并且CSS已被删除。 我将JavaScript移至其自己的文件,并在HTML中添加了对其的脚本引用。 HTML和脚本中有一些不必要的项目。 让我们先来看一下脚本,然后开始使这个最小文件变得更加简约。
At the top of the script, there are three variables to page elements to indicate download and progress. Those are not absolutely necessary. I'm deleting them. I need to delete references to them too. Lower in the JavaScript is a method named setStatus
. I'm replacing its body with a call to console.log()
to print the text that is passed to it. The first set of programs that I'm going to write won't use a canvas. The element isn't needed for now; I'm commenting it out instead of deleting it so that I can use it later. Having deleted the first three lines of this file and code that references them, I'm returning to the HTML. Most of it is being deleted. I've commented out the canvas reference. There is a line in the HTML file with the text {{{ SCRIPT }}}
. The compiler will take this file as a template and replace {{{ SCRIPT }}}
with the reference to the script specific to our Web Assembly file.
在脚本的顶部,页面元素包含三个变量,以指示下载和进度。 这些不是绝对必要的。 我正在删除它们。 我也需要删除对它们的引用。 JavaScript中较低的是名为setStatus
的方法。 我将其主体替换为对console.log()
的调用,以打印传递给它的文本。 我要编写的第一套程序不会使用画布。 目前不需要该元素; 我将其注释掉,而不是将其删除,以便以后使用。 删除了该文件的前三行和引用它们的代码后,我将返回HTML。 大部分被删除。 我已注释掉画布参考。 HTML文件中的一行带有文本{{{ SCRIPT }}}
。 编译器将把这个文件作为模板,并用对我们Web汇编文件特定的脚本的引用替换{{{ SCRIPT }}}
。
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Emscripten-Generated Code</title>
<link rel="stylesheet" href="./styles/emscripten.css" />
<script src="scripts/emscripten.js"></script>
</head>
<body>
<!--
<div class="emscripten_border">
<canvas class="emscripten" id="canvas"
oncontextmenu="event.preventDefault()"></canvas>
</div>
-->
<textarea class="emscripten" id="output" rows="8"></textarea>
{{{ SCRIPT }}}
</body>
</html>
When the Web Assembly program executes a printf()
, the text will be written to the textarea
element. I place my hello.cpp file among these files and then compile it with the following command.
当Web Assembly程序执行printf()
,文本将被写入textarea
元素。 我将hello.cpp文件放在这些文件中,然后使用以下命令对其进行编译。
emcc hello.cpp --shell-file shell_minimal.html -o hello.html
The --shell-file
argument indicates what file to use as a template. The -o
parameter tells the name of the HTML file to write to. If you look at hello.html, you can see it is almost identical to the input template. Run the site now and you'll see the same result, but with a much cleaner interface. Run the program again and you will see the same result with a much cleaner interface.
--shell-file
参数指示要用作模板的文件。 -o
参数指示要写入HTML文件的名称。 如果查看hello.html ,可以看到它几乎与输入模板相同。 现在运行该站点,您将看到相同的结果,但界面更加简洁。 再次运行该程序,您将看到一个更加简洁的界面,结果相同。
绑定功能 (Binding Functions)
I earlier mentioned that Web Assembly doesn't have any bindings to any operating system functions. It also doesn't have bindings do the browser. Nor does it have access to the DOM. It is up to the page that loads the web assembly to expose functions to it. In emscripten.js, the Modules
object defines a number of functions that are going to be made available to the Web Assembly. When the C/C++ code calls printf
, it will be passed through the JavaScript function defined here of the same name. It isn't a requirement that the names be the same, but it is easier to keep track of function associations if they are.
前面我提到过,Web程序集没有任何操作系统功能的绑定。 浏览器也没有绑定。 它也没有访问DOM的权限。 取决于加载Web程序集以向其公开功能的页面。 在emscripten.js中 , Modules
对象定义了许多可用于Web Assembly的功能。 当C / C ++代码调用printf
,它将通过此处定义的同名JavaScript函数传递。 不需要名称相同,但是如果函数名称相同,则更容易跟踪它们。
从JavaScript调用C / C ++ (Calling C/C++ From JavaScript)
But what if you have your own functions that you wish to bind so that your JavaScript code can call the C++ code? The Module
object has a function named ccall
that can be used to call C/C++ code from JavaScript and another function named cwrap
to build a function object that we can hold onto for repeated calls to the same function. To use these functions, some additional compile flags will be needed.
但是,如果您希望绑定自己的函数,以便JavaScript代码可以调用C ++代码,该怎么办? Module
对象具有一个名为ccall
的函数,可用于从JavaScript调用C / C ++代码;另一个名为cwrap
的函数可构建一个函数对象,我们可以保留该函数对象以重复调用同一函数。 要使用这些功能,将需要一些其他的编译标志。
To demonstrate the use of both of these methods of calling C/C++ code from JavaScript, I'm going to declare three new functions in the C++ code.
为了演示这两种从JavaScript调用C / C ++代码的方法的用法,我将在C ++代码中声明三个新函数。
void testCall()
- accepts no parameters and returns no value. This method only prints astring
so that we know that our call to it was successful.void testCall()
-不接受任何参数,也不返回任何值。 此方法仅输出一个string
以便我们知道对其的调用已成功。void printNumber(int num)
- accepts an integer argument and prints it. This lets us know that our value was successfully called.void printNumber(int num)
-接受一个整数参数并将其打印出来。 这使我们知道成功调用了我们的价值。int square(int c)
- accepts an integer and returns the square of that integer. This lets us see that a value can be returned back from the code.int square(int c)
-接受一个整数并返回该整数的平方。 这使我们看到可以从代码中返回一个值。
The C++ language performs what is called name mangling; the names of the functions in the compiled code is different than the uncompiled code. For the functions that we want to use from outside the C++ code, we need to wrap declarations for the functions in an extern "C" block. If our code were being written in C instead of C++, this wouldn't be necessary. I still prefer C++ because of some of the features that the language offers. Normally, I would have a declaration such as this in a header file. But for now, my C++ program is in a single file. Close to the top of the program, I make the following declarations:
C ++语言执行所谓的名称处理。 编译代码中的函数名称与未编译代码不同。 对于要从C ++代码外部使用的函数,我们需要将函数的声明包装在extern“ C”块中。 如果我们的代码是用C而不是C ++编写的,则没有必要。 由于该语言提供的某些功能,我仍然更喜欢C ++。 通常,我在头文件中会有这样的声明。 但就目前而言,我的C ++程序位于单个文件中。 在程序顶部,我做了以下声明:
extern "C" {
void testCall();
void printNumber(int f);
int square(int c);
}
The implementation for the functions is what you would expect.
功能的实现是您所期望的。
void testCall()
{
printf("function was called!\n");
}
void printNumber(int f) {
printf("Printing the number %d\n", f);
}
int square(int c)
{
return c*c;
}
There's a change to my main
method too. I've had to include a new header file, emscripten.h, because I am about to use one of the functions that it provides. In main
, added the following line.
我的main
方法也有所变化。 我必须包含一个新的头文件emscripten.h ,因为我将要使用它提供的功能之一。 在main
,添加了以下行。
EM_ASM ( InitWrappers());
It will result in a JavaScript function named InitWrappers()
to get called. I will talk about how EM_ASM
works in a following section. I'm adding a third <script />
element to my HTML file. The first element contains code that was provided my Emscripten. The second is the one that is inserted where {{{ SCRIPT }}}
exists within the template. The third script tag follows. The third script tag references the JavaScript that contains the InitWrappers
function.
这将导致一个名为InitWrappers()
JavaScript函数被调用。 在下一节中,我将讨论EM_ASM
工作方式。 我要在我HTML文件中添加第三个<script />
元素。 第一个元素包含我的Emscripten提供的代码。 第二个是在模板中{{{ SCRIPT }}}
存在的地方插入的那个。 第三个脚本标签如下。 第三个脚本标签引用包含InitWrappers
函数JavaScript。
var testCall;
var printNumber;
var square;
function InitWrappers() {
testCall = Module.cwrap('testCall', 'undefined');
printNumber = Module.cwrap('testCall', 'undefined', ['number']);
square= Module.cwrap('square', 'number', ['number']);
}
I've declared three variables that will be used to hold the function objects. They are populated by the return values of the cwrap
calls. In the first cwrap
call, the arguments are the name of the C/C++ function to call and the return type. This function isn't returning any value which is why its return type is set to 'undefined'. In the second call, an additional argument is passed; the types of each of the arguments in a list. This function only takes one argument and needs a list with only one element. In the third call, the argument for the return time is set to 'number
' since this method will return a numerical value. To call the functions, I'm adding some JavaScript to the onclick
events.
我已经声明了三个将用于保存功能对象的变量。 它们由cwrap
调用的返回值填充。 在第一个cwrap
调用中,参数是要调用的C / C ++函数的名称和返回类型。 此函数不返回任何值,这就是其返回类型设置为“ undefined”的原因。 在第二个调用中,传递了一个附加参数。 列表中每个参数的类型。 此函数仅接受一个参数,并且只需要一个包含一个元素的列表。 在第三个调用中,返回时间的参数设置为' number
',因为此方法将返回一个数值。 为了调用这些函数,我在onclick
事件中添加了一些JavaScript。
The compile statement is different for this code. A few of these changes are optional. But I will explain all of them.
此代码的compile语句不同。 其中一些更改是可选的。 但我将解释所有这些。
emcc hello.cpp --std=c++11 --shell-file shell_minimal.html
--emrun -o hello.html -s NO_EXIT_RUNTIME=1
-s EXPORTED_FUNCTIONS="['_testCall', '_printNumber','_square','_main']"
-s EXTRA_EXPORTED_RUNTIME_METHODS="['cwrap','ccall']" -s WASM=1
--std=c++11
- I'm using this argument from hereon to enable C++ 11 language features--std=c++11
我从现在开始使用此参数来启用C ++ 11语言功能--shell-file shell_minimal.html
- the name of the shell HTML file to use--shell-file shell_minimal.html
要使用的外壳HTML文件的名称--emrun
--emrun
-o hello.html
- the name of the output html file to produce-o hello.html
要生成的输出html文件的名称-s NO_EXIT_RUNTIME=1
- prevents the runtime from shutting down when the main function exits.-s NO_EXIT_RUNTIME=1
防止在主函数退出时关闭运行时。-s EXPORTED_FUNCTIONS="['_testCall', '_printNumber', '_square']"
- These are the names of the methods that will be added to theModule
object from our code.-s EXPORTED_FUNCTIONS="['_testCall', '_printNumber', '_square']"
-这些是将从我们的代码添加到Module
对象的方法的名称。-s EXTRA_EXPORTED_RUNTIME_METHODS="['cwrap','ccall']"
- these are the names of runtime methods that will be added to theModules
object-s EXTRA_EXPORTED_RUNTIME_METHODS="['cwrap','ccall']"
-这些是将添加到Modules
对象的运行时方法的名称-s WASM=1
emit Web Assembly. Setting this to 0 will cause ASM.js to be emitted instead (something not discussed here).-s WASM=1
发出Web程序集。 将此设置为0将导致发出ASM.js (此处未讨论)。
从C / C ++调用JavaScript (Calling JavaScript from C/C++)
We've already been calling JavaScript from C/C++ implicitly. But let's look at how to explicitly call JavaScript from C/C++. There are two ways of doing this; you can embed JavaScript code directly within your C/C++ code or you can use the function emscripten_run_script()
. If you've ever embedded assembly language in C++ code, then first of these two methods will not look completely foreign to you.
我们已经在隐式地从C / C ++调用JavaScript。 但是,让我们看一下如何从C / C ++显式调用JavaScript。 有两种方法可以做到这一点; 您可以将JavaScript代码直接嵌入C / C ++代码中,也可以使用函数emscripten_run_script()
。 如果您曾经将汇编语言嵌入C ++代码中,那么这两种方法中的第一种对您而言似乎并不陌生。
If there is a block of JavaScript code that you want to repeatedly use within your C++ code, you can write a function in JavaScript using EM_JS
.
如果要在C ++代码中重复使用一段JavaScript代码,则可以使用EM_JS
在JavaScript中编写一个函数。
EM_JS(void,myAlert,(), {
alert('hey, I am alerting you!');
console.log('you have been alerted.')'
});
int main() {
myAlert();
return 0;
}
A new function named myAlert()
is made available because of this call. If JavaScript code is being defined to only be used once, it can be written inline using EM_ASM
:
由于此调用,一个名为myAlert()
新函数可用。 如果将JavaScript代码定义为只能使用一次,则可以使用EM_ASM
内联EM_ASM
:
int main() {
EM_ASM(
alert('hey, I am alerting you!');
console.log('you have been alerted.')'
);
return 0;
}
I would advise against embedding a lot of code within your C/C++. It may be better at most to embed a JavaScript function call; if code needs to be updated, it will be easier to update the JavaScript function than to make the change in the C/C++ code and rebuild.
我建议不要在您的C / C ++中嵌入很多代码。 最多嵌入一个JavaScript函数调用可能更好。 如果需要更新代码,则更新JavaScript函数比在C / C ++代码中进行更改和重建要容易得多。
C ++中的Sun Position (Sun Position in C++)
I wanted to show an example that was doing something non-trivial before closing Part 1 of this article. I've got an interest in astronomical calculations. I've decided to take a C++ routine for calculating the sun position and use it in a web page. After a quick Google search, I found this:
我想展示一个示例,该示例在关闭本文的第1部分之前做了不平凡的事情。 我对天文计算很感兴趣。 我决定采用C ++例程来计算太阳位置并将其用于网页中。 经过快速的Google搜索,我发现了这一点:
I've got to make some changes to use it, but not a lot. The original routine gathered input directly in main
. I don't need to do much of anything in main
. I also don't want to use the cin
object; it results in the input dialog displaying. Instead, I want the parameters to be passed in via a routine. I will leave the cout
calls in place; they
我必须进行一些更改才能使用它,但不是很多。 原始例程直接在main
收集输入。 我不需要做任何main
的事情。 我也不想使用cin
对象; 它会导致显示输入对话框。 相反,我希望通过例程传递参数。 我将离开cout
到位电话; 他们
The main
function will only initialize the wrappers in my modification of the code. I've made a new main
function that calls the JavaScript function to perform initialization.
main
函数只会在我修改代码时初始化包装器。 我制作了一个新的main
函数,该函数调用JavaScript函数来执行初始化。
int main(void){
EM_ASM ( InitWrappers());
return 0;
}
What had been the main
function is being renamed to getSunInformation
. I'm passing in the latitude, longitude, and time zone information and am deleting the previous usage of cin
to prompt the user for this information.
main
功能已被重命名为getSunInformation
。 我要传递纬度,经度和时区信息,并删除cin
的先前用法,以提示用户输入此信息。
void getSunInformation(double latit, double longit, double tzone);
I need to also get information out of this call. While there is more than one way to do this, I'm going to take an easy option for now; I'll have the C++ code call JavaScript code passing the parameters. I can use EM_ASM
to do this. In the earlier use of this function, I was invoking functions. Now I need to pass data. The JavaScript declared within EM_JS
is in a different scope than the C++. It has no visibility on the variables within the C++ code. Any information that we want passed to the JavaScript can be passed in parameters. This information is available in the JavaScript through variables that start with a dollar sign followed by a number for the position parameter. The first parameter is $0
, the next $1
, the third $2
, and so on.
我还需要从此电话中获取信息。 尽管有多种方法可以做到这一点,但现在我将采取一种简单的选择; 我将传递参数的C ++代码调用JavaScript代码。 我可以使用EM_ASM
来做到这一点。 在此功能的早期使用中,我正在调用功能。 现在我需要传递数据。 EM_JS
中声明JavaScript与C ++的作用域不同。 它对C ++代码中的变量没有可见性。 我们想要传递给JavaScript的任何信息都可以在参数中传递。 JavaScript中的信息可以通过以美元符号开头,后跟位置参数数字的变量开头。 第一个参数是$0
,下一个$1
,第三个参数$2
,依此类推。
EM_ASM (
sunParameters($0,$1,$2, $3, $4, $4, $5, $6, $7);
sunNoonParams($8, $9);
sunCurrentPosition($10,$11);
,year,m,day, jd, latit, longit, tzone, delta*degs, daylen
,noont, altmax,
azim*degs,altit
);
I am using three functions we haven't seen yet. The functions sunParameters
, sunNoonParameters
, and sunCurrentPosition
haven't been defined yet. I made a new JavaScript file that will contain these. The emscripten generated JavaScript file is named azimalt.js. My JavaScript file will be appended to this one; I've named it azimAltPost.js. In this file, I define the InitWrappers
function and the three sun
functions that were earlier mentioned. For now, the sun
functions will write the parameters that they receive to the console. The two values passed to getSunInformation
are a latitude and longitude for the Atlanta, Georgia, USA area. If you run the code yourself, you may want to change these.
我正在使用三个尚未见过的功能。 函数sunParameters
, sunNoonParameters
和sunCurrentPosition
尚未定义。 我制作了一个包含这些内容的新JavaScript文件。 由脚本生成JavaScript文件名为azimalt.js 。 我JavaScript文件将添加到此文件; 我已将其命名为azimAltPost.js 。 在此文件中,我定义了InitWrappers
函数和前面提到的三个sun
函数。 现在, sun
函数会将接收到的参数写入控制台。 传递给getSunInformation
的两个值是美国佐治亚州亚特兰大地区的经度和纬度。 如果您自己运行代码,则可能需要更改它们。
var getSunInformation;
function InitWrappers() {
getSunInformation = Module.cwrap('getSunInformation',
'undefined', ['number','number','number']);
getSunInformation(-84,34,-5);
}
function sunParameters(year, month, day, julianDate, latitude, longitude,
timeZone, delta, dayLength) {
console.log(`${year}-${month}-${day}`);
console.log(`Julian Date:${julianDate}`);
console.log(`Latitude:${latitude}, Longitude:${longitude}`);
console.log(`Time Zone: ${timeZone}`);
console.log('Delta: ${delta})');
console.log('Daylength: ${dayLength}')
}
function sunNoonParams(noont,altmax) {
console.log(`Noont: ${noont}, Altitude Max:${altmax}`);
}
function sunCurrentPosition(azim, alt) {
console.log(`Azimuth: ${azim} Altitude:${alt}`);
}
I'm introducing a new compile parameter here, --post-js
. This parameter names a JavaScript file whose content is to be run after the emscripten generated code. I'll be passing my JavaScript file as the value for this argument. The full command line that I'm using to compile this follows:
我在这里引入一个新的编译参数--post-js
。 此参数命名一个JavaScript文件,其内容将在脚本生成的代码之后运行。 我将传递我JavaScript文件作为此参数的值。 我用来编译此命令的完整命令行如下:
emcc azimalt.cpp -o azimalt.html --post-js azimaltPost.js
-s NO_EXIT_RUNTIME=1 -s EXPORTED_FUNCTIONS="['_getSunInformation', '_main']"
-s EXTRA_EXPORTED_RUNTIME_METHODS="['cwrap','ccall']" -s WASM=1
Open the HTML file (make sure it is being served from a web server) and look at the output console. You should see the information on sun rise and sun set for your area.
打开HTML文件(确保从Web服务器提供该文件),然后查看输出控制台。 您应该看到有关您所在地区的日出和日落信息。
自定义日出和日落演示 (Customizing the Sunrise and Sunset Presentation)
The program works, but let's add something graphical to it. I want to add a 24-hour analog clock that at a glance shows the sunrise, sunset, and current position of the sun with respect to the two. I also want a display for a compass to show the azimuth and a graphic to show the altitude angle. I'll use SVG for the graphics. Many of the elements can be declaratively. I came up with the following UI.
该程序可以工作,但让我们在其中添加一些图形化的东西。 我想添加一个24小时的模拟时钟,以一目了然地显示日出,日落和太阳相对于两者的当前位置。 我还希望有一个指南针显示器来显示方位角,并有一个图形来显示高度角。 我将使用SVG进行图形处理。 许多元素都可以声明。 我想出了以下UI。
Before integrating it with the web assembly, I added a few range sliders and JavaScript to make sure that the elements moved the way that I expected them to. Once it was working, I copied the WASM scripts into my new HTML file and it graphically showed me the sunrise and sunset times for today. If you would like to see it yourself, it is available at https://j2i.net/apps/sunrise/. When I tried hosting it on a web server, it initially failed because the server software didn't recognize the WASM extension. If you encounter such a problem, register the mime type for the extension. It is application/wasm
.
在将其与Web程序集集成之前,我添加了一些范围滑块和JavaScript,以确保元素按我期望的方式移动。 运行之后,我将WASM脚本复制到了新HTML文件中,并以图形方式向我显示了今天的日出和日落时间。 如果您想亲自观看,请访问https://j2i.net/apps/sunrise/ 。 当我尝试将其托管在Web服务器上时,它最初失败了,因为服务器软件无法识别WASM扩展。 如果遇到此类问题,请为扩展名注册mime类型。 是application/wasm
。
其他支持的图书馆 (Other Supported Libraries)
But either running emcc --show-ports
or looking at https://github.com/emscripten-ports, you can see some of the other APIs that the enscripten compiler supports. At the time of writing, this is the output from running the command on the command terminal.
但是,无论运行emcc --show-ports
还是查看https://github.com/emscripten-ports ,您都可以看到enscripten编译器支持的其他一些API。 在撰写本文时,这是在命令终端上运行命令的输出。
c:\shares\sdks\emsdk>emcc --show-ports
Available ports:
Boost headers v1.70.0 (USE_BOOST_HEADERS=1; Boost license)
icu (USE_ICU=1; Unicode License)
zlib (USE_ZLIB=1; zlib license)
bzip2 (USE_BZIP2=1; BSD license)
libjpeg (USE_LIBJPEG=1; BSD license)
libpng (USE_LIBPNG=1; zlib license)
SDL2 (USE_SDL=2; zlib license)
SDL2_image (USE_SDL_IMAGE=2; zlib license)
SDL2_gfx (zlib license)
ogg (USE_OGG=1; zlib license)
vorbis (USE_VORBIS=1; zlib license)
SDL2_mixer (USE_SDL_MIXER=2; zlib license)
bullet (USE_BULLET=1; zlib license)
freetype (USE_FREETYPE=1; freetype license)
harfbuzz (USE_HARFBUZZ=1; MIT license)
SDL2_ttf (USE_SDL_TTF=2; zlib license)
SDL2_net (zlib license)
cocos2d
regal (USE_REGAL=1; Regal license)
c:\shares\sdks\emsdk>
When you use one of these libraries, the emscripten compiler will retrieve the library, built it locally, and link it to your project.
当您使用这些库之一时,emscripten编译器将检索该库,在本地构建它,并将其链接到您的项目。
第二部分是什么 (What's in Part 2)
I have some ideas about what to write about in part 2 of this series such as how to deal with complex data types and binding to classes. But I want to hear from you. What would you like to see? Share your ideas and questions in the comments; I'd like to respond to some of them in the next post in this series.
我对本系列第二部分中的内容有一些想法,例如如何处理复杂的数据类型以及如何绑定到类。 但我想听听您的消息。 你想看见什么? 在评论中分享您的想法和问题; 我想在本系列的下一篇文章中对其中一些做出回应。
翻译自: https://www.codeproject.com/Articles/5250727/Introduction-to-Web-Assembly-with-C-Cplusplus
c ++反汇编与逆向分析