当前位置:首页 >> 安全

“C 不再是一种编译器!”

来源:安全   2024年11月11日 12:16

也有。

仍要你就会推测,每个人都不必学就会C才能与当今的作业系统展开交互,然后当所需相互间对话时,大家顿时都用起了C。既然如此,为什么不直接用C来展开交互呢?

过去C就变回了一种程序员非标准语言学,不仅是一种脚本语言学,它还是一种两国政府了。

与C展开交互限于哪些内容?

很明显,大体上每种语言学都不必学就会与C展开交互,而且这种语言学实际上上是比较明确的。

"Talking"C是什么含意?它显然以C常量的基本赢取API类别和一新功能的描绘,并以某种模式:

匹配这些类别的结构设计 用客户端器做到一些过扯情,将变量的大撰写字母类比为指针 用相应的ABI来codice_这些变量(比如把args放在准确的数据流之前所)

那么,这里就有几个关键问题:

你仅仅不用撰写一个C类比器 C仅仅没ABI,甚至没以界定的类别结构设计

仅仅很难类比一个C常量

Aria曾断言类比C大体上是不也许的,但有人话说其实有很多工具可以习取C常量,比如rust-bindgen。过扯实果真如此吗?其实不然。

bindgen应用做libclang来类比C和C++常量。要修正bindgen查看libclang的模式,请参阅clang-sys文档。关于bindgen如何应用做libclang的非常多先前所,请参阅bindgen浏览器指南。

任何耗费大量时间段试绘出短时间段内类比C(++)常量的人都就会很快打消,然后让一个C(++)脚本语言来做到这件过扯。请记下,有意义地类比C常量不仅仅是类比:你还所需克服#includes、typedefs和macros的关键问题!所以过去不仅要实现所有相关一新功能,还要实现所有一新游戏平台的常量类比逻辑,并且还所需只不顾一切找DEFINED!

就拿Swift来话说,它在与C展开应用软件和海洋资源总体具备实际上上优势,它是由草莓开发设计的基础知识脚本语言学,合理取代了Objective-C,如此一来为在其一新游戏平台上以界定和应用做系统API的主要语言学。在这样做到的现实生活之前所,它比其他任何人都非常只想进一步实现ABI稳以定和基本概念设计。

它也是Aria认出的最背书FFI的语言学之一。它可以本地导入(Objective-)C(++)常量,并转化成一个漂亮的本地SwiftAPI,其类别在边界自动 "桥接 "到它们的Swift对等项(由于类别有着大致相同的ABI,所以往往是绿色的)。

Swift的许多开发设计者同时也是实现和维护Clang和LLVM的开发设计团队。这些人都是C及其的有总体的全球性顶级医学专家。Doug Gregor就是其之前所之一,他曾传达了对C FFI的论调:

可以看出,即使是Swift也不只想白花时间段类比C(++)常量。那么,如果你实际上上不只想让C脚本语言在解释器时类比和克服常量,你该怎么做到呢?

你所需工艺中文翻译! int64_t ? 还是撰写 i64. long …?什么是long?

C仅仅没ABI

好吧,这没什么好懊恼的:C语言学之前所的整数类别,为了 “开放性”而被设计如此一来大小不一不固以定。我们可以显然CHAR_BIT很奇特,但这也不用为了让我们了解long 的大小不一和倒置模式。

有人话说每个一新游戏平台都有标准本土化的codice_话说好和ABI,确实有,而且它们往往以界定了C之前所关键之前所文中文翻译的结构设计(并且有些不只是用C类别来以界定codice_话说好,参考AMD64 SysV)。

还有一个棘手的关键问题:的系统并没以界定ABI,作业系统也没。我们不必在一个特以定的要能假定上尽力,比如 “x86_64-pc-windows-gnu”(绝不会和 "x86_64-pc-windows-msvc "混淆)。经过测试,一共有176个假定。

>rustc --- printtarget-list

aarch64-apple-darwinaarch64-apple-iosaarch64-apple-ios-macabiaarch64-apple-ios-simaarch64-apple-tvos

...armv7-unknown-linux-musleabiarmv7-unknown-linux-musleabihfarmv7-unknown-linux-uclibceabihf...x86_64-uwp-windows-gnux86_64-uwp-windows-msvcx86_64-wrs-vxworks>_

ABI无论如何是太多了,因为测试之前所甚至没中用所有相异的codice_话说好,如stdcall vs fastcall或aapcs vs aapcs-vfp。

但据估计所有这些ABI和codice_话说好之类都可以用一种方便应用做的机器可习格式赢取。据估计当今的C脚本语言在特以定要能假定的ABI上达如此一来了恰当! 当然有一些奇特的jank C脚本语言,但Clang和GCC不是:

> abi-checker---testsui128---pairsclang_calls_gccgcc_calls_clang

...

Testui128::c::clang_calls_gcc::i128_val_in_0_perturbed_smallpassedTestui128::c::clang_calls_gcc::i128_val_in_1_perturbed_smallpassedTestui128::c::clang_calls_gcc::i128_val_in_2_perturbed_smallpassedTestui128::c::clang_calls_gcc::i128_val_in_3_perturbed_smallpassedTestui128::c::clang_calls_gcc::i128_val_in_0_perturbed_bigfailed! test57 arg3field0 mismatchcaller: [30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 3A, 3B, 3C, 3D, 3E, 3F]callee: [38, 39, 3A, 3B, 3C, 3D, 3E, 3F, 40, 41, 42, 43, 44, 45, 46, 47]Testui128::c::clang_calls_gcc::i128_val_in_1_perturbed_bigfailed! test58 arg3field0 mismatchcaller: [30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 3A, 3B, 3C, 3D, 3E, 3F]callee: [38, 39, 3A, 3B, 3C, 3D, 3E, 3F, 40, 41, 42, 43, 44, 45, 46, 47]

...

392 passed, 60 failed, 0 completelyfailed, 8 skipped

上面是Aria在Ubuntu 20.04 x64上直通的FFI abi-checker,她在这个非常关键的、表现良好的一新游戏平台上测试了一些比较乏味的Demo。结果推测,一些整数变量在两个由Clang和GCC解释器的连续性努中间按值传递受挫了!

Aria推测,Clang和GCC甚至不用就Linux x64上_int128 的ABI达如此一来恰当。

Aria本来是为了检查rustc之前所的误判,没只记得就会在一个关键的、常用的ABI上推测值得一提当今C脚本语言的不恰当。

试绘出驯服C

Aria显然,好像的是对C常量展开语义类比,只能由该一新游戏平台的C脚本语言来完如此一来。即使C脚本语言去找了你类别和如何理解注释,但仅仅你几乎不其实所有内容的大小不一/倒置/惯例。那如何与这些乱七八糟的外面展开应用软件呢?Aria给予了两种为了让。

第一个为了让是所谓打消,将你的语言学与C展开灵魂绑以定,这可以是下述任何一种:

用C(++)改撰写脚本语言/直通时,这样它就可以用C了 让你的 "codegen "直接聚合C(++),这样浏览器无论如何都所需一个C脚本语言 将脚本语言创设在一个茁壮的主要C脚本语言(Clang或GCC)最上层

即使做到到上面这些,也不就会让你的脚本语言走多远,除非你的语言学是不是受伤害了unsigned long long ,否则你将后继者C的巨大开放性混乱。

这就让我们只记得了第二个为了让:撒谎、骗子和偷窃。

如果这一切是无论如何都很难不致的浩劫,你还不如开始工艺中文翻译类别和API以界定,大体上就是我们每天在Rust之前所所做到的过扯情。比如,人们应用做rust-bindgen和friends电子本土化处置一些过扯,但很多时候,以界定就会被检查或工艺修正。因为人们不只想浪费时间段去尝试Phantomderp的以定制C实现系统可移植地指导。

在Rust之前所,Linux x64上的intmax_t是什么?

pub typeintmax_t = i64;

在Nim之前所,Linux x64上的long long是什么?

clonglong {.importc: "long long", nodecl.} = int64

很多标识符早就所谓打消将C保证在循环之前所,开始对核心类别的以界定展开硬编码。毕竟,它们显然只是一新游戏平台ABI的一部分!他们要相反intmax_t 的大小不一吗?这显然是一个冲击ABI的叠加!

那phantomderp将要研究的又是什么?

我们讨论过为何 intmax_t 不用被相反,因为如果我们从 long long (64位整数)改名 _int128_t (128位整数),某个偏远地区的十六进制就会失控应用做误判的codice_话说好/返回话说好。但有没一种步骤,如果标识符为了让了它或其他外面,我们可以为较重一新该软件系统升级变量codice_,而让上一新该软件保证不变?让我们改撰写一些标识符,测试一下绿色别名可以为了让ABI的或许。

Aria驳斥了她的异议:脚本语言学如何处置这种叠加?如何指以定与哪个修正版的 intmax_t 交互?如果你有一些C常量提到intmax_t ,它应用做的是哪个以界定?

在此讨论有着相异ABI的一新游戏平台的主要组态是要能假定。你其实什么是要能假定吗?你其实大体上涵盖了过去20年里所有当今桌面/服务器Linux的软件的 x86_64-unknown-linux-gnu 都有什么吗?过去,虽然表面上可以针对这个要能展开解释器,并得到一个在所有这些一新游戏平台上都能“但会指导”的十六进制副本,但Aria不相信有些程序中就会被解释器如此一来intmax_t 等于int64_t 。

任何试绘出做到出这种相反的一新游戏平台都就会如此一来为一个重一新x86_64-unknown-linux-gnu2 要能假定吗?如果任何针对x86_64-unknown-linux-gnu 解释器的外面都被无需在上面直通,这难道还不够吗?

在不冲击ABI的才会变非常收件

"那又怎样,C忍耐不就会再有退步吗?"不!但也是!因为他们给予了拙劣的设计。

老实话说,展开ABI可选的修正是一种艺术基本。这种艺术的一部分就是马上指导。具体内容来话说,如果你马上好了,做到出不冲击ABI的修正就就会较难得多。

正如phantomderp的撰文所指出的,像glibc(g 是x86_64-unknown-linux-gnu 之前所的gnu )早就忘记了这一点,并应用做大撰写字母修正版本土化这样的组态来非常一新收件和API,同时为任何针对上一新修正版解释器的人原有上一新修正版。

因此,如果你有int32_t my_rad_symbol(int32_t) ,你去找脚本语言将其导出为my_rad_symbol_v1 ,那么任何根据这个常量展开解释器的人,都就会在他们的标识符之前所撰写上my_rad_symbol ,但针对my_rad_symbol_v1 客户端。

然后当你决以定仅仅应该应用做int64_t 时,你可以把int64_t my_rad_symbol(int64_t) 作为my_rad_symbol_v2 ,但原有上重一新以界定作为 my_rad_symbol_v1 。任何针对较一新修正版常量展开解释器的人都就会高兴地应用做v2大撰写字母,而针对上一新修正版展开解释器的人则一直应用做v1!

但是你几乎有一个可选性的关键问题:任何用一新常量解释器的人都不用与努的上一新修正版展开客户端,努的V1修正版根本没V2大撰写字母!因此,如果你只想赢取热门的的软件,你就要给予与上一新系统的不可选。

不过这未必是什么大关键问题,它只是让一新游戏平台营运商感到伤心,因为没人必需立刻应用做他们白花了这么多时间段做到的外面。你一再推出一个闪亮的的软件,然后让大家等待它来得足够普遍和茁壮。但为了人们想要仰赖它并受阻对上一新一新游戏平台的背书(或者想要为它施行建模检查回退)时,你不必坐等几年。

如果你是不是只想让人们立刻系统升级,那就要发表意见后退可选的关键问题。这让上一新修正版的外面以某种模式与他们没基本概念的的软件一起指导。

在不冲击ABI的才会变非常类别

那除了可以相反一个变量的收件,还可以相反类别结构设计吗?Aria问到,这取决于你是如何受伤害类别的。

C真正奇妙的一个在结构上是,它可以让你区分一个可知结构设计的类别和一个推断出结构设计的类别。如果你只在C常量之前所前所向声明一个类别,那么任何与之交互的浏览器标识符都不被“无需”其实该类别的结构设计,并且不必始终在指针后面不绿色地处置它。

所以你可以做到一个像MyRadType* make_val 和use_val(MyRadType*) 的API,然后应用做同样的大撰写字母修正版熟练来受伤害make_val_v1 和use_val_v1 大撰写字母,任何时候你只想相反这个结构设计,你就在所有与该类别交互的外面上提高修正版。类似地,你在MyRadTypeV1 、MyRadTypeV2 和一些类别以界定之前所原有了一些,以确保人们应用做“准确”的类别。这样就可以在相异的修正版中间相反类别的结构设计。

如果多个外面创设在你的努最上层,然后开始用不绿色类别相互间闲聊,坏过扯就就会发生:

lib1: 制作一个API,给予 MyRadType* 并codice_ use_val lib2:codice_ make_val 并将结果传递给lib1

如果lib1和lib2针对努的相异修正版展开了解释器,那么make_val_v1 就就会被转换到use_val_v2 之前所!你有两个为了让来处置这个关键问题:

1.话说这是被全面禁止的,责问那些无论如何都要这么做到的人,然后伤心

2.以一种后退可选的模式设计MyRadType ,这样混就可以了

少见的前所向可选熟练都有:

原有未应用做的数组供未来修正版应用做 MyRadType的所有修正版都有一个共同的大撰写字母,可以让你“检查”你所应用做的修正版 具备自以定大小不一的数组,以便上一新修正版可以“跳过”重一新部分

系统性研究:MINIDUMP_HANDLE_DATA

Linux是这种后退可选的艺术大师,甚至可以实过去的系统中间保证结构设计可选。Aria最近将要处置的一个例子是Minidumpapiset.h 之前所的MINIDUMP_HANDLE_DATA_STREAM。

这个API描绘了一个有修正版的值本表。该本表以这种类别开始:

typedefstruct _MINIDUMP_HANDLE_DATA_STREAM {ULONG32SizeOfHeader;ULONG32SizeOfDeor;ULONG32NumberOfDeors;ULONG32Reserved;}MINIDUMP_HANDLE_DATA_STREAM, *PMINIDUMP_HANDLE_DATA_STREAM;

其之前所:

SizeOfHeader 是MINIDUMP_HANDLE_DATA_STREAM本身大小不一。如果他们所需在仍要提高非常多的数组,那也没父子关系,因为上一新修正版可以应用做这个值来检验头的“修正版”,也可以跳过任何他们不其实的数组。 SizeOfDeor 是数组之前所每个金属元素的大小不一。这让你其实你有什么 "修正版 "的金属元素,并跳过任何你不其实的数组。 NumberOfDeors 是数组长度 Reserved 是一些额外的内核,无论如何他们决以定原有在常量之前所(Minidumpapiset.h比较严肃,从不在任何偏远地区展开装入,因为装入字节有未指以定的值,而且它是一种序列本土化的十六进制副本格式。我努力他们加到这个数组是为了使构件的大小不一是8的平方根,这样就不就会有任何关于数组金属元素在标题在此之后到底所需装入的关键问题。这是在认真对待可选性!)

而过扯实上,Linux仅仅有理由应用做这种修正版方案,并以界定了两个修正版的数组金属元素:

typedefstruct _MINIDUMP_HANDLE_DEOR {ULONG64Handle;RVATypeNameRva;RVAObjectNameRva;ULONG32Attributes;ULONG32GrantedAccess;ULONG32HandleCount;ULONG32PointerCount;} MINIDUMP_HANDLE_DEOR, *PMINIDUMP_HANDLE_DEOR;typedefstruct _MINIDUMP_HANDLE_DEOR_2 {ULONG64Handle;RVATypeNameRva;RVAObjectNameRva;ULONG32Attributes;ULONG32GrantedAccess;ULONG32HandleCount;ULONG32PointerCount;RVAObjectInfoRva;ULONG32Reserved0;} MINIDUMP_HANDLE_DEOR_2, *PMINIDUMP_HANDLE_DEOR_2;

//The latest MINIDUMP_HANDLE_DEOR definition.typedefMINIDUMP_HANDLE_DEOR_2 MINIDUMP_HANDLE_DEOR_N;typedefMINIDUMP_HANDLE_DEOR_N *PMINIDUMP_HANDLE_DEOR_N;

这些构件的实际上先前所不是很有趣,除了:

他们只是通过在末尾加到数组来相反它 有一个“月所修正版”的类别以界定 原有了一些比如话说之后Padding(装入)(RVA是一个ULONG32)

这是一个坚不可摧的后退可选的庞然大物。它们对装入比较小心,它甚至在32位和64位中间有大致相同的结构设计 (这仅仅是比较关键的,因为你努力一个的系统上的minidump晶片组必需处置来自每个的系统的minidump)。

系统性研究:jmp_buf

Aria对这种情形不是很感兴趣,但在研究历史上的glibc受阻时,她在LWN上碰到了一篇很棒的撰文:《glibc s390 ABI受阻》,她断言它是准确的。

过扯实证明,glibc曾多次密码过类别的ABI,据估计在s390上。根据这一段话的描绘,它是混乱的。

特别是他们相反了setjmp/longjmp应用做的保留静止状态类别的结构设计,即jmp_buf 。过去,他们其实这是一个冲击ABI的叠加,所以他们做到了负责任的大撰写字母修正版本土化的过扯情。

但jmp_buf 未必是一个不绿色的类别,其他外面都在并行地读取这个类别的范例,比如Perl的直通时间段。不用话说,这个相对晦涩的类别早就发挥作用许多十六进制副本之前所去了,再度的结论是,Debian的所有外面都所需重一新解释器!

这一段话甚至讨论了将libc修正版系统升级以遏制这种情形的风险:

在像debian这样的混ABI环境之前所,SO名称碰撞导致两个libc被加载并争夺大致相同的大撰写字母取名为空间,而类比(以及因此为了让ABI)则由ELF滤波和以内原则上决以定。这真是一场未来世界。这也许是一个比去找大家重建并一直生活非常拙劣的克服方案。

是不是能相反intmax_t吗?

在Aria看来,不所谓是。就像jmp_buf 一样,它不是一个不绿色的类别,这显然它被并行到大量的随机构件之前所,被显然有着大量其他语言学和脚本语言的特以定问到,并且也许是大量公共API的一部分。而这些API未必在libc、Linux,甚至不在的软件捍卫者的依靠之下。

当然,libc可以相应地应用做大撰写字母修正版熟练来使其API与重一新以界定可选,但相反像 intmax_t 这样的大体数据类别的大小不一,是在一个一新游戏平台的大生态系统之前所寻求混乱。

Aria努力被证明自己是误判的,但据她知晓,做到出这样的相反所需一个重一新要能假定,并且不无需任何为上一新ABI实现的十六进制/努在这个一新假定上直通。当然有人可以做到这些指导,但Aria未必眼里任何这样做到的的软件。

以致于,遭遇的还有x64的int关键问题:这是一个比较大体的类别,而且多年来始终是这种大小不一,无数的该软件也许对它有奇特的很难查觉的断言。这就是为什么int在x64上是32位的,尽管它应该是64位的:int是32位的时间段以致于了,以至于所谓终究将软件非常一新到重一新大小不一,尽管它是一个全重一新的系统和要能假定。

Aria之后努力自己是扯的,但是人们有时犯的误判如此严重,以至于根本很难挽回。如果C语言学是一种所谓的脚本语言学?当然可以去做到。但它不是,它是一个两国政府,还是我们不必应用做的拙劣的两国政府。

就算C臣服于了全球性,但比如话说它再也给与好外面了。

END

重庆妇科检查多少钱
重庆白癜风治疗费用
济南儿科检查
昆明男科医院哪家医院最好
武汉看肝病哪个医院好
关节保护
湿气重肠胃不舒服怎么办
普乐安片和坦洛新可以同时吃吗
佐米曲普坦片服用方法
打呼噜药多少钱一盒
友情链接