Repository navigation
Use PE/COFF AOT snapshots for Windows x64 - #187594
Conversation
There was a problem hiding this comment.
Code Review
This pull request adds support for compiling and linking Windows x64 AOT snapshots into a DLL using Visual Studio's linker. Feedback on the changes includes a recommendation to remove {BUILD_DIR}/app.pdb from the build target outputs to prevent breaking incremental builds when --split-debug-info is enabled. Additionally, it is suggested to simplify embedder.cc by removing the redundant ResolveAOTSnapshotSymbol helper function and calling ResolveSymbol directly.
bf60403 to
b5aed1f
Compare
|
Thanks for sending this patch! FYI, we'll hold off on reviewing this until the Dart SDK CL lands: https://dart-review.googlesource.com/c/sdk/+/511320 |
|
Dart has merge the DLL support in https://dart-review.googlesource.com/c/sdk/+/511320. So we are able to go on, first I should change author to [email protected] before I go on |
|
Is there a reason why Dart SDK change only implements PE/COFF for x86_64? It seems quite weird still requiring ELF loader on arm64. |
There are three main reasons for this change:
|
|
@linzj I think knopp was asking a different question: should we use PE/COFF AOT snapshots for Windows Arm64 too? |
|
This pull request is not mergeable in its current state, likely because of a merge conflict. Pre-submit CI jobs were not triggered. Pushing a new commit to this branch that resolves the issue will result in pre-submit jobs being scheduled. |
894dfea to
e60c74d
Compare
|
fyi this caused a 20% improvement in startup time: cc @walley892 since you've been looking into startup time |
@loic-sharma Is it okay to add an optional param for building in old ELF? New PE DLL format has a lot of negatives sides i think people don't want to pay just to add a better debug info for cases that happen too rarely (i see the
Old format did not have these issues |
The other issues needs to be looked at, but the false positive needs to be reported until they fix their broken heuristics. There's no way around that. We can't be expected to ship ELF on windows just so that we please some broken antivirus heuristics. Btw. only one antivirus flagging this is actually surprisingly good result, sadly. |
But ELF did not have this problem. I understand heuristics are broken, but what they'll do is just add 1 file hash to their clean list and problem won't be fixed, 1 is surprisingly good but it's default flutter counter app - no extra packages, no functions. Will PR with extra flag for old format be accepted if proposed? New will remain as is, just 1 param to build with what was already stable and working fine for those who don't want to change anything to worse |
The size doesn't really matter. I had false positives consistently generated for NSIS uninstaller executable which is tiny. It's also not just adding hashes. I never had false positive with cynet but I had with many other anti-viruses and after several reports they all actually fixed the heuristics.
I can't really answer that, but personally I'd rather see the issues diagnosed and fixed. Shipping ELF on Windows was always a hack. I think we would prefer to ship native binaries. |
|
Btw. can you explain what the point of obsfucating the Dart code on windows is? There are no debug symbols inside PE/COFF files, what is the point of additional obsfucation? It think it has been conceded that the obsfucation will not work for windows. |
Personally i never used it, just a scenario of how people use the current format Obfuscation doesn't depend on debug symbols. The same PE build without --obfuscate prints innerFrame (package:symtest/main.dart:21) A few open sources repos i found withing 2 minutes on git:
What changed for them with PE/COFF: Is it a problem for them? I don't know. I personally did not like the false positives trigger out of nowhere, absolute pdb path from machine and different hash on each build ### I understand flutter can not depend on a few repos and will not try to avoid breaking changes for a tiny amount of people who use that, but i can't see anything wrong for keeping support for format that's already working for years and does not have any obvious issues except for that debug stack trace problem |
|
Again, what is the point of renaming symbol if the symbols only exist in the PDB file that is never shipped to customers? PE/COFF does not have any symbol names in the binary itself.
There shouldn't be any symbols in the COFF. It's not impossible but it's deprecated. The symbols should only be inside PDBs. I assumed this was already happening but maybe the assumption was wrong.
It's something that adds complexisty and that we need to support and keep maintaining. There is some cost associated with it. |
I'm not sure what cost are you referring to, format remains for ARM and Linux, it's already there, it was already used for years. The change to add a flag for optional ELF format in Flutter is about 116 added and 28 removed lines outside of tests: an option in flutter_tools and a format check on load in the engine. Obfuscation doesn't touch native symbols. It renames Dart class, function and library names that are stored in the snapshot data itself, in .rdata. The runtime uses them for stack traces and runtimeType.toString(), without any PDB. In the counter app the COFF symbol table is empty (NumberOfSymbols = 0), yet .rdata still contains strings like package:counter/main.dart. That's why a PE build prints innerFrame (package:symtest/main.dart:21) without reading the PDB, and bUa (Byb:21) with --obfuscate. The extra size is Dart's own stack trace data (CodeSourceMaps). The ELF build drops it with --dwarf-stack-traces, the PE build doesn't pass that flag. With the flag added by hand the PE app.so is 2,771,968 bytes vs 2,786,264 for ELF. But the PDB has no Dart functions or line info (2 public symbols, 0 procedures), so such stack traces can't be symbolized. That's why it isn't passed |
I'm referring to the complexity of having something configurable and have to keep supporting two paths on single platform. Yes, ARM64 still needs ELF but that's missing implementation rather than by choice. And it's not a flag.
The source of native symbols are dart classes and methods.
I assumed this also works with PDB but I guess I was wrong. In this case optionally still supporting ELF on windows makes more sense. |
|
@krll-kov thanks for the detailed testing. The "2 public symbols, 0 procedures" observation is correct, but it's a bug in how flutter_tools drives gen_snapshot, not a limitation of PE/COFF. Root cause flutter_tools passes The same check also gates Verification I used a small Dart program with the same gen_snapshot and
Planned follow-up
This doesn't address DLL file locking or the antivirus heuristics. Those are product trade-offs for the ELF-option discussion in #194854. |
|
@krll-kov A huge thank you for the excellent feedback before this landed on stable. @linzj Thanks for the analysis. From my understanding of your planned follow-up work:
And like you said, this won't address the DLL file locking or antivirus heuristics. Is my understanding correct? Assuming my understanding is correct, I'd recommend we revert this PR. Item 1 seems like a definite prerequisite before we reland this PR. However, I lean towards also making item 3 a prequisite before relanding. What do people think? |
If decided not to revert or decision is delayed until the next stable release, is it okay to enable old format as optional flag in |
|
@loic-sharma Mostly yes, with one correction on item 3:
The regression only affects apps built with Item 3 prototype I prototyped item 3 to check it's feasible. gen_snapshot can write the same separate DWARF debug file for PE/COFF that it already writes for ELF and iOS. The Dart change is small:
flutter_tools then passes the same flags it uses on ELF platforms: Results on a small Dart program built with
So with item 3, PE/COFF ends up slightly smaller than ELF instead of larger. One dependency: Still open
Revert I'm fine with reverting. My plan for relanding:
|
|
Update: I've started on item 3 on the Dart side: https://dart-review.googlesource.com/c/sdk/+/568321 The CL:
It adds a PE/COFF variant to |
|
I want to provide high-level commentary: we absolutely certainly want to use native executable/object/debugging information formats on all platforms. Dart AOT snapshots should just be understood by native tooling and OS specific dynamic linkers. This means using ELF on Linux, Mach-O on Mac and it PE/COFF on Windows. We used ELF on Windows because it was simpler this way. If we get PE/COFF output to parity with ELF output in terms of capabilities we most certainly want to switch away from ELF format and delete all and any support for using ELF on Windows. In that vein: I think debugging information should also be represented by OS specific format. I don't think it makes sense to bend backwards and use DWARF on Windows. It should be PDB based. |
|
Following @mraleph's suggestion, I've dropped the DWARF-on-Windows approach (abandoned https://dart-review.googlesource.com/c/sdk/+/568321) and switched to PDBs. I'm starting with the Dart SDK side:
With these, the Once they land and roll into Flutter, I'll do the flutter_tools side:
I'll post updates here as the CLs progress. |
|
Reason for revert: See the comments above: |
|
Failed to revert commit 95bdb98 cleanly. Please resolve conflicts manually. |
Thanks @loic-sharma. To confirm the reland plan: I'll finish the Dart SDK side first (PDB support in Also, the revert bot couldn't revert this cleanly because of conflicts. Would you like me to open a manual revert PR? |

Summary
Enables Windows x64 profile/release AOT bundles to consume a PE/COFF AOT DLL instead of the previous ELF snapshot path.
This change:
app-aot-pecoff-objfor Windows x64 onlylink.exe--split-debug-info, the PDB is written only to the split symbols directoryCompanion Dart SDK PR: https://dart-review.googlesource.com/c/sdk/+/511320
Validation
dart formatover the changed flutter_tools Dart files andclang-formatover the changed engine C++ files.python flutter/testing/run_tests.py --variant=host_debug_unopt --type=engine --engine-filter=flutter_windows_unittestsflutter_windows_unittests.exe --repeat=2ninja -C out/host_profile_unopt gen_snapshot flutter_windowsflutter createWindows x64 profile app with the local engine and--extra-gen-snapshot-options=--no-strip.build/windows/x64/runner/Profile/data/app.soisCOFF-x86-64and exports only_kDartSnapshotDataand_kDartSnapshotText.datadirectory contains no PDB; the CodeView debug directory points at.dart_tool/flutter_build/.../app.pdb.llvm-readobj --unwind app.soreports 8211RuntimeFunctionentries and 47 sharedUnwindInfoAddressvalues.cdbthat a breakpoint inapp!RenderObject.layout+0xbunwinds through Dart AOT frames, Flutter native frames, and Windows system frames.Representative
cdb kvstack excerpt: