跟我们一起
玩转路由器

史上最黑的黑科技--把chromium 的blink、v8、skia用vc6的crt编译并运行!

这个想法由来已久,其原因有三个显著的优势:

1、可以忽略VS2015的MD版本所需的那些api-xxxx-xxx的dll文件。这些文件数量庞大,令人头疼。

2、可以不必处理manifest的问题。这东西非常烦人,设置稍有不慎就会导致各种无法加载的问题。特别是本机没问题,但客户机上可能就会出现问题。

3、小巧。vc6版本只需要msvcp60.dll和mscrt.dll,这两个文件在所有Windows系统中都自带,非常方便。这意味着可以节省MT版本所需的额外空间。实际上,Windows的所有dll文件基本上都是依赖这两个文件运行的,Windows自己用得非常顺畅,只是没有明确告诉我们如何使用。

现在的目标非常明确,就是将miniblink所使用的VS2015的crt替换为vc6的crt。

这个过程非常艰难。毕竟vc6的crt与最新版本的crt差异巨大,多次我都以为这是不可能完成的任务,差点放弃。但又觉得不甘心,坚持查阅资料,最终居然成功了。

真可谓是山穷水尽疑无路,柳暗花明又一村。

首先是搭建环境。我们需要一套DDK的包,将其中的inc和lib目录提取出来,然后设置到VS2015的工程中。实际上就是清空VS2015的目录,并将其设置为DDK的目录:

然后就可以开始编译了。

接下来就是大量的编译错误……

我们一个个地解决。

首先解决blink工程中的问题。

举个例子,如上图所示,blink自己编写的deque使用了stl的std::reverse_iterator,但这个模板参数在老版本中发生了变化,需要传入T这个模板参数。因此,在这里针对vc6的rt添加了一个参数。

虽然说起来简单,但在编译过程中,错误提示是一屏接一屏的,所以你能理解当时的心情……

耐心地一个个修改。

然后是更麻烦的与Windows相关的头文件和宏缺失的问题。比如缺少GdiAlphaBlend等。这很麻烦,因为数量巨大……

但最后我还是全部补上了。无非就是从新版头文件中复制缺失的部分,放到一个单独的头文件中,然后让所有工程都引入。

如果在链接时找不到,那就需要动态调用了。这都是工作量的问题,说起来简单,但要知道一次就缺了几十个相关的函数,而且每次添加一个都可能面临rebuild……

然后是令人头疼的__int64问题。vc6的crt,很多stl的重载没有x64版本……比如ostream& operator

最后也是我一点点添加的。

blink相关的工作完成后,轮到v8了。本以为这个简单,因为与操作系统相关的部分较少,没想到也很麻烦。

v8子类化了几个stl的类,比如ZoneVector。但老版本的一些接口又变了,具体如图所示:

无非就是适配老版本stl的模板接口。不过编译的错误又是大量抛出……心情很郁闷。

其他的也是些零碎的api和宏需要补充。

接下来谈谈skia的问题。

其中最大的麻烦是,skia使用了大量的sse、xmm指令,而老crt没有这些指令!

当时我震惊了,因为如果要手写这些指令的汇编,工作量将非常巨大……

但就在我快要绝望的时候,我发现,那堆_mm_cmpeq_ss之类的函数,只要声明了,VS2015就可以内置进去!

原来这些是内置函数(可以搜索VS内置函数)。

于是我直接拿过来新版本的xmmintrin.h等几个头文件,修改了编译错误,居然让VS成功编译了!而且skia的部分也都通过了……当时我泪流满面,差点就放弃了。

编译问题解决后,剩下就是链接问题了。这里也很麻烦,一链接,就抛出了几千个链接错误……大部分是找不到api,这个好解决,动态调用一下就行了。

但有几个麻烦的地方:

一个是_Init_thread_header、_Init_thread_footer等几个函数找不到。这些函数在网上几乎找不到有用的信息(后来知道是内置函数,在一些lib中),于是我先用空函数代替。但这些函数的参数类型和返回值完全不知道,而且VS一旦参数不对,编译也通不过。所以只能靠猜……最后居然被我猜出来了,是void _Init_thread_header(int*)类型的,当时我又泪流满面了……

其他编译错误就不提了,总之都是巨大的工作量,几千个错误要改。

最后终于编译通过,但运行起来又是各种问题。还是刚才的_Init_thread_header的问题。这货居然会插入在每个局部静态变量的前面,用来保证线程安全的局部静态变量的初始化。

但这货还用了几个如__tls_index之类的全局变量,这些需要初始化,但初始化的函数根本没生成,因为初始化的函数所在的lib是VS的新版crt中的。当时搞了很久,想了个很不好的方案,就是搜索特征码,把这个__tls_index的地址拿到手,然后自己去初始化……不过幸运的是,群里有人告诉我,这玩意是VS新版的特性,叫Static local variables are initialized in a thread-safe,

其实是有

/Zc:threadSafeInit-这个开关可以关闭的!

这个真是救了我。把这个开关关闭后,果然_Init_thread_header之类的函数也不会生成了,所以也不需要我写空函数代替了……

Thread-safe “magic” statics: Static local variables are initialized in a thread-safe way,

removing the need for manual synchronization.

Be aware that usage of these variables other than initialization is still not protected.

Thread safety can be disabled by using

/Zc:threadSafeInit- to avoid a dependency on the CRT.

最后是一些还没解决,但不影响的问题,就是有几个stl的操作符重载,一直提示链接不到。比如

basic_ostream<char, char_traits > & __cdecl operator<< ( basic_ostream<char, char_traits > & a, basic_string<char, char_traits , allocator > const & b)

但我查看了mscrt.dll,这个函数确实是导出的。最后不管了,写了个本地的函数代替,内部直接调用mscrt.dll。

然后是一堆sse的函数找不到,比如_libm_sse2_sin_precise _libm_sse2_pow_precise _libm_sse2_acos_precise这些。差点在这里又放弃了。

还好找到一篇文章,讲这玩意是VS的新特性,可以通过设置里代码生成的无增强指令 (/arch:IA32)来关闭对高级sse指令的编译优化。

再然后是一些数学库找不到,比如nextafterf之类的。老版的crt没有。这个我从苹果的llvm中扣到具体的代码。

见:https://www.php.cn/link/80f5c854f86f7ecdd80a84b2973a9b08

最后的最后,终于成功运行miniblink~!!!!!!!!!!!!!!!!!!!!!!!!!!

赞(0)
版权声明:本文采用知识共享 署名4.0国际许可协议 [BY-NC-SA] 进行授权
文章名称:《史上最黑的黑科技--把chromium 的blink、v8、skia用vc6的crt编译并运行!》
文章链接:https://www.lu-you.com/settings/28394.html
本站资源来源于互联网整理,若有图片影像侵权,联系邮箱429682998@qq.com删除,谢谢。

评论 抢沙发

登录

找回密码

注册