Obtaining return address during lowerCall()

I’m implementing a more secure calling convention (on the CHERI fork of llvm, but my question is applicable to vanilla llvm as well).

A part of this calling convention is returning using what is called an “activation record”, a small bundle of code and data placed on the stack which when executed restores the environment of the caller.

To construct this activation record I need to obtain a return address, ie the address of the first instruction after RISCVISD::CALL.

As stated in the title, I am working in the lowerCall() function (in RISCVISelLowering.cpp), so the return address will have to be some variable which is filled in during machine code emission. My question is: where can I obtain that variable during call lowering?

If I can provide more information to illustrate the problem further, I am more than happy to do so.
Thanks!

Not sure if I really understood your problem, but can’t you just create a MCSymbol representing a label after RISCVISD::CALL, and making sure that you emit that label in the AsmPrinter? Depending on place you need to access that label, you can either store in in the RISCVMachineFunctionInfo, or refer to it with a MCSymbolSDNode in the DAG.

I’m having trouble positioning the label correctly.
In lowerCall nodes are created in this order:

ISD::Store node which should contain a reference to the label.
… (other instructions)
ISD::Call
ISD::CALLSEQ_END

To attach the label to the ISD::CALLSEQ_END node I use createLocalDirectionalLabel to obtain an MCSymbol which I then attach to the node with getLabelNode(ISD::ANNOTATION_LABEL,...).
However, in the end the label ends up being attached to the expansion of the store node. I suspect this is because the label node is attached to the store node.

How can I force this label to be attached to the ```ISD::CALLSEQ_END`` node?

Code on the stack requires an executable stack, something we have been very deliberately not supporting in the pure-capability ABI for CHERI. Both the virtual memory mapping and the stack capability are RW not RWX.

You need to be careful how you do this and think about whether you want that to be a sentry capability or not. I’m assuming you’re sealing your activation record capability, in which case you don’t need a sentry in there, but it still would be nice to not add more non-sealed code capabilities lying around.

Having an executable stack is indeed a concern of us, which we would like to address with indirect sentry capabilities.
If you’re interested in more detail about the calling convention I’m implementing, please have a look at this paper which introduces it and formalizes the security guarantees it provides.
My work consists of gauging the performance penalty paid when using this calling convention. As such I am just interested in implementing the basic components of the CC, to evaluate their impact.