前言:
而今咱们对“c语言 web”都比较着重,各位老铁们都想要了解一些“c语言 web”的相关资讯。那么小编也在网上搜集了一些对于“c语言 web””的相关文章,希望你们能喜欢,看官们快快来学习一下吧!点击链接阅读原文,获取更多技术内容:WebAssembly 入门-阿里云开发者社区
本文是一篇WebAssembly的入门文章,从理论介绍到实战方面有全面的讲述。
作者 | 子肃
来源 | 阿里开发者公众号
历史进程
由于 javascript 的动态类型特性,AOT 并不能为它做出优化,只能选择 JIT 来优化。
而为了让 JIT 效率提高,Mozilla 推出了 asm.js。它和 Typescript 比较相似的是它也是一个强类型语言,不过它的语法是 js 的子集,它专为 JIT 效率提高而打造。
在 Mozilla 推出 asm.js 之后,一些公司都觉得这个思路不错,于是联合起来推出了 WebAssembly。
WebAssembly 是什么
WebAssembly 是一套指令集(字节码)标准,不过它并不是可以被 CPU 直接执行的原生指令集,所以它目前还需要配套一个虚拟机(low-level)来执行。
工具链
目前比较成熟的有
1、(基于 LLVM)
2、(Rust)
我们这里拿 emscripten 举例,它可以让任何使用 LLVM 作为编译器后端的语言都可以编译到 wasm。
这是怎么做到的呢?我们先了解一下 LLVM。
LLVM
Low-Level-Virtual-Machine
它是一个编译器,不过它不直接将语言编译到机器码,而是先用每个语言的前端编译器编译到 IR(intermediate representation),然后再利用后端编译器编译到目标机器码。这样设计的好处是在需要支持一个新架构时,只需要添加一个后端编译器就可以了。
而 WebAssembly 就是这么多编译目标中的一个,所以任何基于 LLVM 的语言都可以编译到 WebAssembly。
既然这样,我们可以试试直接采用 LLVM 来编译 wasm,体验一下原汁原味的过程。
实战
安装 LLVM
brew install llvmbrew link --force llvmllc --version# 确保 wasm32 在 targets 中
编译 C
假设我们有 C 文件 add.c
int add(int a, int b) { return a * a + b;}
第一步:我们先采用 clang 将 C 文件编译到 LLVM IR
clang \ --target=wasm32 \ -emit-llvm # 生成 LLVM IR, 而不是直接生成机器码 -c \ # 仅编译(no linking) -S \ # 生成可读的 wat 格式, 而不是二进制格式 add.c
我们会得到一个 add.ll 文件,这就是 LLVM IR,大概长下面这个样子
; ModuleID = 'add.c'source_filename = "add.c"target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"target triple = "wasm32"; Function Attrs: noinline nounwind optnonedefine hidden i32 @add(i32 noundef %0, i32 noundef %1) #0 { %3 = alloca i32, align 4 %4 = alloca i32, align 4 store i32 %0, ptr %3, align 4 store i32 %1, ptr %4, align 4 %5 = load i32, ptr %3, align 4 %6 = load i32, ptr %3, align 4 %7 = mul nsw i32 %5, %6 %8 = load i32, ptr %4, align 4 %9 = add nsw i32 %7, %8 ret i32 %9}attributes #0 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" }!llvm.module.flags = !{!0}!llvm.ident = !{!1}!0 = !{i32 1, !"wchar_size", i32 4}!1 = !{!"Homebrew clang version 15.0.7"}
第二步:将 LLVM IR 编译到 object 文件
llc -march=wasm32 -filetype=obj add.ll
我们会得到一个 add.o,它是一个含有这个 C 文件所有编译代码的 wasm 模块,不过现在还不能够运行它。这个模块中其实是一个可以被阅读的格式,我们可以用一些工具来解析它,比如 WebAssembly Binary Toolkit(wabt)
brew install wabtwasm-objdump -x add.o
大概长这样
add.o: file format wasm 0x1Section Details:Type[1]: - type[0] (i32, i32) -> i32Import[2]: - memory[0] pages: initial=0 <- env.__linear_memory - global[0] i32 mutable=1 <- env.__stack_pointerFunction[1]: - func[0] sig=0 <add>Code[1]: - func[0] size=44 <add>Custom: - name: "linking" - symbol table [count=2] - 0: F <add> func=0 [ binding=global vis=hidden ] - 1: G <env.__stack_pointer> global=0 [ undefined binding=global vis=default ]Custom: - name: "reloc.CODE" - relocations for section: 3 (Code) [1] - R_WASM_GLOBAL_INDEX_LEB offset=0x000006(file=0x00005e) symbol=1 <env.__stack_pointer>Custom: - name: "producers"
这里定义了 add 方法,不过除此以外还包含了很多其他信息,比如 imports,这其实是要被下一个环节(linking)所消费的
第三步:Linking
一般来说,连接器的作用是将多个 object 文件连接成一个可执行的文件。
LLVM 中的连接器叫做 lld,根据编译目标不同存在多个 lld,我们这里要用的是 wasm-ld
wasm-ld \ --no-entry \ # add.c 并没有一个入口文件, 它是一个 lib --export-all \ # 导出所有方法 -o add.wasm \ add.o
这里我们会得到最终的 wasm 产物,add.wasm
剩余60%,完整内容请点击下方链接查看:WebAssembly 入门-阿里云开发者社区
阿里云开发者社区,千万开发者的选择。百万精品技术内容、千节免费系统课程、丰富的体验场景、活跃的社群活动、行业专家分享交流,尽在:阿里云开发者社区-云计算社区-阿里云
标签: #c语言 web