Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【实现建议】不用IDMAP,只使用IDTagAttribute。 #34

Closed
treert opened this issue Oct 14, 2019 · 20 comments
Closed

【实现建议】不用IDMAP,只使用IDTagAttribute。 #34

treert opened this issue Oct 14, 2019 · 20 comments

Comments

@treert
Copy link
Contributor

treert commented Oct 14, 2019

老项目的dll,注入了3万5千多个函数,生成IDMAP在ios的il2cpp阶段出错了。
Unity 5.6.7f1的il2cpp对字段数量的限制是32767【这应该是Unity.IL2CPP的bug】。

看了下iFix实现,如果直接用IDTag来标识函数唯一int索引,应该也没有问题。
现在IDTag主要为了重载函数准备的。

自己尝试建了个XIDAtrribute,使用有效,生成的dll还变小了。

感觉没必要使用IDMAP,直接用IDTag来标记不是挺好的。有什么特殊考虑吗?

@treert treert changed the title 【实现建议】不是IDMAP,只使用IDTagAttribute。 【实现建议】不用IDMAP,只使用IDTagAttribute。 Oct 14, 2019
@chexiongsheng
Copy link
Collaborator

dll变小,是指clr程序集么?
我以前的测试,标注一个Attribute,il2cpp后代码量挺大的,会为每一个Attribute生成一个初始化函数。这点你可以确认下。
对于“il2cpp对字段数量的限制是32767”,把一些第三方的库排除掉试试?

@treert
Copy link
Contributor Author

treert commented Oct 15, 2019

是clr程序集变小了,因为里面没有IDMAP了。il2cpp后的代码到没有关注。

il2cpp对字段数量的限制是32767,这个应该是Unity的bug,应该是上限是65535,我把unity安装包里的dll反编译修改后,就可以了打出ios包了。

@treert
Copy link
Contributor Author

treert commented Oct 15, 2019

ipa包体增加6M多,还可以接受。
1.31GB (1,404,329,736 字节)
1.30GB (1,398,143,846 字节)

il2cpp虽然会生成创建Attribute的函数,但是应该是每次GetCustomAttribute时调用一下,只多了些内存。
直觉IDMAP里的枚举字符串名字肯定也要在某个地方存储,虽然没在cpp的代码里搜到。

@chexiongsheng
Copy link
Collaborator

“IDMAP里的枚举字符串”是反射信息的一种。应该是用文件来存储。
如果il2cpp实现的没太挫的话,这些信息应该不用常驻内存的。

@chexiongsheng
Copy link
Collaborator

还有每个attitude也是要有反射信息的

@chexiongsheng
Copy link
Collaborator

6M多不能和1.31G的包体比,应该和代码段比。而且苹果对应用的代码段是有大小限制的。

@treert
Copy link
Contributor Author

treert commented Oct 15, 2019

我们这个项目特别情况,解决编译问题得三选一

  1. 修改unity安装目录里的dll。
  2. 修改Ifix的补丁索引实现。
  3. 少导出类。

代码段大小对我们项目不是问题了,ios 9.0 以上是400M,所以选择了第2个。

@chexiongsheng
Copy link
Collaborator

有的项目还是挺case那几M代码段大小的。
你现在是已经修改并跑成功了么?

@treert
Copy link
Contributor Author

treert commented Oct 17, 2019

嗯,跑成功了。很小的改动,增加了个XIDAttribute。
还有额外的好处,这样对注入函数的数量限制就变大了非常多,Load时查询索引的速度应该会变快。

改Unity的dll也成功了,但有些不放心,算是做个两手准备。

@wpdever
Copy link

wpdever commented Oct 25, 2019

请问官方有解决方案了吗?我们也遇到这个问题了, Unity 2018.4.7

IL2CPP error for type 'IFix.IDMAP' in assembly '/xxx.../Data/Managed/Assembly-CSharp.dll'
Additional information: Value of type 'int' is too large to convert to ushort.

@treert
Copy link
Contributor Author

treert commented Oct 25, 2019

可以先参考我的实现,改下,在我fork的库里的local分支上的最近一次提交。
treert@980d318
官方不知道会不会这么改了。

@joywater
Copy link

@treert 我把你的local代码下载下来,重新编译,放到工程里,生成的patch有问题
Unhandled Exception:System.NullReferenceException: Object reference not set to an instance of an object
at IFix.CecilExtensions.getAssemblyFullName (Mono.Cecil.TypeReference typeReference) [0x00000] in E:\ProjectTest\InjectFix1\InjectFix\Source\VSProj\Src\Tools\CecilExtensions.cs:133
at IFix.CecilExtensions.GetAssemblyQualifiedName (Mono.Cecil.TypeReference typeReference, Mono.Cecil.TypeReference contextType, System.Boolean skipAssemblyQualified, System.Boolean skipAssemblyQualifiedOnce) [0x001bb] in E:\ProjectTest\InjectFix1\InjectFix\Source\VSProj\Src\Tools\CecilExtensions.cs:259
at IFix.CodeTranslator.Serialize (System.IO.Stream output) [0x003e8] in E:\ProjectTest\InjectFix1\InjectFix\Source\VSProj\Src\Tools\CodeTranslator.cs:3427

@treert
Copy link
Contributor Author

treert commented Oct 29, 2019

是个bug,修复了。注释掉两个文件,各一行代码,就好了。
treert@8efbc8c

@Magneto235
Copy link

Magneto235 commented Nov 26, 2019

@chexiongsheng 我们也遇到函数个数太大,IDMAP过大问题,如果能保证生成Patch时,工程和原注入的dll只有修复的函数会变化,那么是否能保证patch时函数的id和原函数的id的一致的?如果一致的话,是不是可以直接把id写进patch里,而不需要用函数签名的方式来查找IDMAP的对应域来找id,这样感觉可以去掉IDMAP?

@chexiongsheng
Copy link
Collaborator

1、总不能需要用户保证函数的不增不减;
2、即使不增不减,也是“应该”id不会发生变化。
最早是patch写id,但是由于你得知道之前分配的id是啥,所以以前版本的ifix得输入原来的dll,通过原来的dll获取当时分配了啥id。所以项目得保留已经注入好的线上项目对应的dll。
但是有个大项目,在全球各地区都有不同的版本,他们要保留很多版本的dll,对他们来说十分繁琐,所以改成了现在这样。

treert的方式是对代码段大小有一定的影响,很多项目对这还是比较在乎的。

不过按理说,如果去掉一些第三方库,一般自己写的代码没那么多吧?

@Magneto235
Copy link

Magneto235 commented Nov 26, 2019

@chexiongsheng 非常感谢解答,我们的项目由于5+年,函数有10W+了,即便筛掉一些感觉不容易出错的,也还是有8 - 9W,单个IDMAP不能了,除非是实现分段IDMAP0~n,比如每1w个值存放在一个;目前只好用用XIDAttribute方式,代码段的话,估计IDMAP也要占用的吧(每个函数签名不短,估计跟XIDAttribute的占用差不多了),另外,““IDMAP里的枚举字符串”是反射信息的一种。应该是用文件来存储,不常驻内存” 这个很难说,访问过搞不好就一直在内存了(这个我没实测);

@chexiongsheng
Copy link
Collaborator

treert测试过了, 他们项目多了6M,不是内存,是代码段。

@chexiongsheng
Copy link
Collaborator

@treert 我打算修改这问题,加下我QQ讨论下?

@treert
Copy link
Contributor Author

treert commented Mar 17, 2020

@treert 我打算修改这问题,加下我QQ讨论下?

你QQ号是啥

@chexiongsheng
Copy link
Collaborator

@wpdever @joywater @Magneto235
最新的提交已经解决了这个问题。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants