-
Notifications
You must be signed in to change notification settings - Fork 56
关于可靠的新旧世界 ELF 文件标记 #31
Comments
cc @yetist @xry111 @scylaac @ChenghuaXu P.S. 上面提到的 |
还涉及内核、发行版,添加 cc @sunhaiyong1978 @chenhuacai |
这种兼容预期是到啥程度?新世界内核可以 chroot 运行旧世界用户态? |
应该可以直接运行,在新世界的系统上, 直接运行基于旧世界打造的闭源程序,比如wps等 |
这个很有难度:
|
这个做不到,有结构体定义变了,访问字段的 offset 等等东西会不兼容,预期最彻底只能做到 chroot 级别的兼容,同一个 sysroot 不大可能同时兼容两种的(除非魔改 libc,我不认为这种能过上游) |
有NSIG,chroot也不行。 |
意思是 chroot 里放一个基于 ptrace 拦截、翻译系统调用的静态 shim,然后只要内核能 100% 准确检测到旧世界程序,用这个 shim 执行起来,就可以兼容了。没有 shim 当然不可能直接兼容。 |
这个并不必要吧,LFS 从 glibc-2.33 升级到 2.34 的时候没有发现这个问题,我自己在 LoongArch 上编译系统也没有遇到这个问题。 glibc-2.34 提供了空的 libpthread.a 和 libpthread.so.1,理论上应该足够向下兼容。 |
这个是最烦的。我的想法是引入一组和旧 ABI 兼容的系统调用 (上游很可能不会接受,但是可以写成单独的内核模块),然后用 LoongArch 的二进制翻译扩展在运行旧代码时把系统调用号直接改掉。但是并不知道可不可行,毕竟二进制翻译扩展的细节还没公开。 |
或者能否用 personality 机制 ( |
在我的 Gentoo 移植工作中,这个调整是必须的,否则链接有问题。
不够:正因为是空的,新世界 |
这个事情前面提到的
这个貌似也是合适的做法,但仍然绕不过如何可靠检测 personality 的问题。 |
ptrace 的问题是如果系统调用比较多 (比如频繁 read/write 文件) 会很慢。 |
空的 libpthread.so.1 链接到了 libc.so.6,它应该包含过去 libpthread.so 包含的所有符号。 符号名称也和它在哪个库没关系,不应该找不到啊…… 如果找不到的话应该是动态链接的实现或者配置有问题。 |
其实呢,这个问题最简单的解法是“没有旧世界”。大家可能认为旧世界已经定型,一成不变了,实际上并不是。比如最近调整什么pt_regs结构啊,重命名UAPI里面的一些变量啊啥的,一直在导致旧世界不断变化。只不过这些变化都是温水煮青蛙式的,不像NSIG那样混搭根本起不来,把大家吓得不要不要的。我主张旧世界以改动pt_regs和重命名变量为契机,顺带着把旧世界直接消灭好了(NSIG一并改掉),希望大家支持。 |
这是最棒的,非常支持。 |
支持。“学得更好,用得更好,彻底批判旧世界,创造新世界。” |
合入上游之前,如果还可以调整,新的 ELF 可以通过定义新的 EI_ABIVERSION 来做出区分。 如果已经没有机会再改动 ABI 规范,可以试试通过 .note.ABI-tag 里面记载的内核最低版本要求来区分新老 ELF(可用 file 命令检查看看)。前提是商业系统不会再往上升级内核版本。 |
glibc中 |
好吧,那如果定义 EI_OSABI,明确区分两种 ABI 呢? |
e_flags 31bit咋样?因为这种差异不是因主动设计abi引起的,而是其他原因引起的不兼容,不管是放在EI_OSABI还是目前LoongArch预留的e_flags[7:3]都不合适,直接单独放1bit表示一下,目前的旧世界都是0,新世界置1区分一下。 |
我觉得能在一个符合规范、容易处理的字段里区分出来就好,然后新旧世界之间不准 interlink 应该也是要做的。 具体实现姿势我目前没太强的倾向性,先看看大家的想法呗? |
如果要动 eflags ,那可以新世界的 ABI 版本 ( |
我们现在可以确认的是,所有旧世界程序都是 LP64D ABI,但旧世界表示 LP64D 的方法是让 |
我的意思是新世界从 |
哦哦,值域别撞就行,这一块我没特别的偏好,你们先讨论着就好 |
请问一下新世界ABI大概什么时候有结论?我看给Go的elf没有相关描述。 https://go-review.googlesource.com/c/go/+/342324/25/src/debug/elf/elf.go |
如果你问的是新的非栈机模型 ELF 重定向记录的工作,按照我的理解,没有社区提案,龙芯公司不会推进新的 ELF 重定向记录类型工作,因为他们目前的做法也是内部开会认为够用的。 这里讲的新旧世界,主要是最根本的 kernel ABI 兼容性问题:完全不能互操作的两个分裂生态。这个问题与 ELF 重定向记录类型不便实现的问题是正交的,新/旧世界搭配旧/新 ELF 重定向记录的两两组合,都是可以工作的,只是可能无法 interlink 而已。 |
这样是否能接受:划定4位出来作为操作系统 (内核,动态链接) 特性相关的标记,其含义取决于
对于 这样可能的好处是:子程序 ABI 和 OS ABI 之间是相对独立的,并且 OS ABI 需要分配的 |
我觉得可以,不过我觉得取 [11:8] 位,然后 [31:12] 保留比较好。 |
欸,我突然发现 ELF executable 里面不是有内核版本嘛:
那我们直接认为 ABI >= 5.19.0 的是新世界就行了? |
只有可执行文件有这个标记,区分不了库 |
使用 考虑到有后一种需求的人都是开发者,而近几年为 LoongArch 做开发的同学客观上都必须了解一些新旧世界的概况,我们倒是可以先基于这个做一版方案,先把最终用户想跑程序的需求解决了。 |
继续主张没有“旧世界”方案。 |
“没有旧世界”其实就是“旧世界演化为新世界”,但这样的前提是商业发行版、下游 ISVs 都全部重新编译;在此之前至少一两年内还是会有人不升级自己的(旧世界)系统,然后就仍然会遇到问题。最终用户混搭软件遇到运行失败,是问题;ISVs 纠结自己要给哪个世界编包、QA,也是问题。并且从资本的角度考虑,第二个问题的结论大概率会是支持旧世界,进而第一个问题中的最终用户为了“能用”,也得选旧世界。因此解决新旧世界问题的关键仍然是龙芯何时推动厂商重做系统。 |
有 #61 后,这个是不是也可以关了。 |
这样一来,其实就是以新 relocs 代表新世界;只要旧世界永远不支持新 reloc types,倒是可以拿它代表一下。我觉得都行。 使用旧 relocs 的新世界是一个中间状态,这些不兼容也罢。现阶段新世界用户都被警告过住的是毛坯房,重装就重装吧。 |
#61 已经合并,新世界 ABI 也已稳定一段时间了。可以进行下一阶段任务了,本 issue 的目的已经达到。 感谢所有同学的热情参与! |
很不幸,
Linux 有 目前 Linux 也不会检查 感觉很僵硬。。 |
同学们,现在到了做取舍的时候:
按照目前(可能)唯一可行的 如果你有更多一些想法可以帮助我(和水深火热之中的旧世界用户),也欢迎贴出来讨论。 |
解释一下:这不是在为旧世界招魂,也不是给厂商一个不迁移到新世界的理由。这更多是技术方案上的探索,以便万一有这需求了可以实现。正常的思路是“当作旧世界不存在”,甚至连 |
给我整不会了,我还真不知道 Musl 没有 |
众所周知,目前准备推上游的 LoongArch 内核-用户界面 ABI 与早已出货的几种商业发行版并不兼容:
libpthread.so
不是 stub,而从上游角度,LoongArch glibc 自始没有分立的libpthread.so
;NSIG
、struct sigcontext
等等内容与上游接受的内容不同,由于早期 LoongArch 生态的建设没有征询社区意见,而导致了这些现状:LoongArch 生态自始就分裂为两套互不兼容的体系,来自一个世界的 userland 无法在另一个世界的内核上正常工作。
尽管我们无法回到过去解决这些问题,但好在新旧世界的不兼容性目前仍然可控,因此可以尽早设计出适配方案,以实现新世界对旧世界闭源软件的兼容。预期未来随着 LoongArch 支持逐渐合入上游,各大商业发行版迟早都会 rebase & rebuild 到新世界,因此可以暂时不考虑旧世界上执行新世界应用的场景。
目前对于动态链接的可执行文件,可以通过 ELF interpreter 路径来区分新旧世界的程序。但对于静态链接的情况,需要有别的方式来可靠确定当前进程的 flavor,以便在需要的时刻正确截获、翻译系统调用。
这里先把问题抛出来,看看社区里大家都怎么想。我自己的方案可能一两天内整理好发出来。
The text was updated successfully, but these errors were encountered: