This is an archive of the discontinued LLVM Phabricator instance.

[AArch64] Add asm directives for the remaining SEH unwind codes
ClosedPublic

Authored by mstorsjo on Aug 31 2020, 12:43 PM.

Details

Summary

Add support in llvm-readobj for displaying them and support in the asm parsser, AArch64TargetStreamer and MCWin64EH for emitting them.

The directives for the remaining basic opcodes have names that match the opcode in the documentation.

The directives for custom stack cases, that are named MSFT_OP_TRAP_FRAME, MSFT_OP_MACHINE_FRAME, MSFT_OP_CONTEXT and MSFT_OP_CLEAR_UNWOUND_TO_CALL, are given matching assembler directive names that fit into the rest of the opcode naming; .seh_trap_frame, .seh_context, .seh_clear_unwound_to_call

The opcode MSFT_OP_MACHINE_FRAME is mapped to the existing opecode enum UOP_PushMachFrame that is used on x86_64, and also uses the corresponding existing x86_64 directive name .seh_pushframe. TODO: Or should it be given a name that is consistent with the other ones, e.g. .seh_machine_frame?

Diff Detail

Event Timeline

mstorsjo created this revision.Aug 31 2020, 12:43 PM
mstorsjo requested review of this revision.Aug 31 2020, 12:43 PM

Adding assembler support for the basic opcodes we left out because the code generator doesn't use them seems fine. We could teach the assembler to optimize certain constructs: for example, turn save_regp_x into save_r19r20_x if the register matches and the offset is in range. Might be more confusing than helpful, though.

For the custom stack opcodes, do you have some intended use? If we just want to allow people to dump random bytes into the unwind opcode list, we could add a directive for that, without trying to come up with an appropriate name for opcodes that aren't really documented.

Adding assembler support for the basic opcodes we left out because the code generator doesn't use them seems fine. We could teach the assembler to optimize certain constructs: for example, turn save_regp_x into save_r19r20_x if the register matches and the offset is in range. Might be more confusing than helpful, though.

Yeah, I've thought about that kind of optimizations. One could also use the save_next opcode a bit to shrink out a few bytes here and there.

I'm a bit on the fence about what level to do it at, though. It'd be neat to do it e.g. at the MC/Win64EH.cpp level, but then you'd have a situation where assembler level constructs don't map 1:1 to what actually ends up emitted - I'm not sure if that's an issue in practice though.

But that's for later anyway.

For the custom stack opcodes, do you have some intended use?

Yes, I have an actual usecase for this. Within the wine implementation of ntdll, there's a case where unwinding needs to be diverted. If the wine ntdll is built as an ELF (or MachO), those unwinding rules can be done with dwarf escape codes, but if the wine ntdll is built as a PE, it needs one of these opcodes. The corresponding case for x86_64 was implemented like this recently: https://source.winehq.org/git/wine.git/commitdiff/c76dc32feffaeed260bf73499e43012b69bee1b4 This one used .seh_pushframe there (which is the only option there), while for aarch64 I guess it could either be done with MSFT_OP_CONTEXT or MSFT_OP_MACHINE_FRAME. My tentative implementation of the same uses MSFT_OP_CONTEXT.

If we just want to allow people to dump random bytes into the unwind opcode list, we could add a directive for that, without trying to come up with an appropriate name for opcodes that aren't really documented.

I guess that's a possibility as well. The opcodes here are documented in the sense that they are listed with a name, but their exact behaviour isn't described. Anybody actually using them needs to study their behaviour themselves (which can be done with e.g. RtlVirtualUnwind). I've documented the behaviour of two of them empirically by testcases in https://source.winehq.org/git/wine.git/commitdiff/bc3284f818f70d2de0bc76beaa69a3352f27fd34.

@efriedma Any followup to the discussion above?

Regarding just allowing passing custom opcode bytes through vs defining names - it's only 4 odd ones, so a custom escape mechanism feels a bit overkill, and they at least have names in the docs.

efriedma accepted this revision.Sep 2 2020, 2:43 PM

LGTM

Regarding just allowing passing custom opcode bytes through vs defining names - it's only 4 odd ones, so a custom escape mechanism feels a bit overkill, and they at least have names in the docs.

Fair enough.

This revision is now accepted and ready to land.Sep 2 2020, 2:43 PM
This revision was landed with ongoing or failed builds.Sep 3 2020, 1:12 AM
This revision was automatically updated to reflect the committed changes.