Skip to content
This repository was archived by the owner on Mar 15, 2022. It is now read-only.

[WIP] Support Arm32 and Arm64 in nearDiff - #1098

Closed
echesakov wants to merge 4 commits into
dotnet:masterfrom
echesakov:SupportLiteralPoolOnArm64
Closed

[WIP] Support Arm32 and Arm64 in nearDiff#1098
echesakov wants to merge 4 commits into
dotnet:masterfrom
echesakov:SupportLiteralPoolOnArm64

Conversation

@echesakov

Copy link
Copy Markdown

Right now CorDisTools can not be used to disassemble JIT output during SuperPMI with ARM64 JIT due to the fact that on ARM64 the code block is appended with literal pool (https://github.com/dotnet/coreclr/blob/06f1634c3157dc279779f3dad7d2f327416e3f09/src/jit/emit.cpp#L4629-L4650)

What happens is that the disassembler goes beyond JIT code and tries to decode data in literal pool where it obviously fails.

I couldn't find any information collected during JIT-EE interactions that can help to determine the size of JIT code region. It seems that we are loosing such information during allocMem call by explicitly passing 0 in roDataSize (https://github.com/dotnet/coreclr/blob/06f1634c3157dc279779f3dad7d2f327416e3f09/src/jit/emit.cpp#L4645)

What I am doing here is trying to reconstruct boundary between JIT code and constant pool during instruction decoding by looking at LDR instructions that have PCRel immediate as a second operand and computing the corresponding label addresses using current value of PC. The minimum address is then assumed to be the beginning of a literal pool.

I did experimentation with running SuperPMI with ARM64 JIT with CorDisTools with these changes and it seems that this approach works on the all framework libraries in Core_Root.

@dotnet/jit-contrib
Does anyone think about a better way to figure out the literal pool size?
@briansull @BruceForstall

@AndyAyersMS

Copy link
Copy Markdown
Member

We could put some invalid instruction padding in between the end of the actual code and the literal pool, and have the disassembly tools know what that means.

@RussKeldorph

Copy link
Copy Markdown

Other ways that change what the JIT does and wastes a small amount of space or time:

  • If you don't want to increase the distance between the code and the literals, could you write the size or offset of the literals at the end of the allocated block?
  • Add a dummy API or parameter to the JIT-EE interface that conveys this info?

Hard to think of something simpler than what you're doing that doesn't add extra meta-data, though. If you can discover all the code entrypoints from the JIT-EE interactions, you could do flow analysis to find live code and treat everything else as data. That seems insane, though, unless we started interleaving data with code, and even then I think you're method would work most of the time.

I apologize for my JIT ignorance, but do we generate switch tables as inline data? If so, that data may need to be discovered as well.

constexpr unsigned int AArch64_LDRSl = 2407;

bool HasPCRelLabel = false;
unsigned int OperandNum = -1;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Who do you need this var?

break;
}

if (HasPCRelLabel) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't it be replaced with Inst.getOpcode() == AArch64_LDRDl || Inst.getOpcode() == AArch64_LDRSl?

switch (Inst.getOpcode()) {
case AArch64_LDRDl:
case AArch64_LDRSl:
HasPCRelLabel = true;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the formatting is broken here.

Comment thread lib/CoreDisTools/coredistools.cpp
return false;
}

const uint8_t* ConsBlockL = nullptr;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please add a comment or longer names for these two variables?

@echesakov echesakov changed the title [WIP] Support literal pools at the end of code section on Arm64 [WIP] Support Arm32 and Arm64 in nearDiff Jun 2, 2019
@BruceForstall

Copy link
Copy Markdown

It seems like this is a bit of a hack to me.

On the one hand, if we want to support disassembling blobs of code that might also contain data, we should do something more sophisticated like construct a flow graph, and binary compare any bits between the "found" native code.

For this case, it feels like we should extend the "allocMem" JIT-EE interface method to take a "roCloseDataSize" that would be added by the VM to the code size, the way our call to allocMem does currently. (Actually, it seems like we should create roCloseHotDataSize and roCloseColdDataSize.) With this, SuperPMI would get the right info.

@echesakov

Copy link
Copy Markdown
Author

Closing in favor of dotnet/jitutils#291

@echesakov echesakov closed this Sep 19, 2020
@echesakov
echesakov deleted the SupportLiteralPoolOnArm64 branch September 19, 2020 03:43
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants