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

Add program property and PLT for CFI extension #417

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 99 additions & 6 deletions riscv-elf.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -643,15 +643,29 @@ The PLT (Procedure Linkage Table) exists to allow function calls between
dynamically linked shared objects. Each dynamic object has its own
GOT (Global Offset Table) and PLT (Procedure Linkage Table).

RISC-V has defined several PLT styles, which used for different situation,
the default PLT sytle should be used if the program is not met the condition for
using all other PLT sytle.

[[plt-style]]
.PLT styles
[cols="1,2"]
[width=70%]
|===
| Default PLT | -
| Unlabeled landing pad PLT | Must use this PLT style when `GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED` is set.
|===

The first entry of a shared object PLT is a special entry that calls
`_dl_runtime_resolve` to resolve the GOT offset for the called function.
The `_dl_runtime_resolve` function in the dynamic loader resolves the
GOT offsets lazily on the first call to any function, except when
`LD_BIND_NOW` is set in which case the GOT entries are populated by the
dynamic linker before the executable is started. Lazy resolution of GOT
entries is intended to speed up program loading by deferring symbol
resolution to the first time the function is called. The first entry
in the PLT occupies two 16 byte entries:
resolution to the first time the function is called.

The first entry in the PLT occupies two 16 byte entries for the default PLT style:

[,asm]
----
Expand All @@ -665,11 +679,29 @@ in the PLT occupies two 16 byte entries:
jr t3
----

Subsequent function entry stubs in the PLT take up 16 bytes and load a
function pointer from the GOT. On the first call to a function, the
entry redirects to the first PLT entry which calls `_dl_runtime_resolve`
and fills in the GOT entry for subsequent calls to the function:
And occupies three 16 byte entries for the simple landing pad PLT style:
[,asm]
----
1: lpad 0
auipc t2, %pcrel_hi(.got.plt)
sub t1, t1, t3 # shifted .got.plt offset + hdr size + 16
l[w|d] t3, %pcrel_lo(1b)(t2) # _dl_runtime_resolve
addi t1, t1, -(hdr size + 16) # shifted .got.plt offset
addi t0, t2, %pcrel_lo(1b) # &.got.plt
srli t1, t1, log2(16/PTRSIZE) # .got.plt offset
l[w|d] t0, PTRSIZE(t0) # link map
jr t3
nop
nop
kito-cheng marked this conversation as resolved.
Show resolved Hide resolved
nop
----

Subsequent function entry stubs in the PLT take up 16 bytes.
On the first call to a function, the entry redirects to the first PLT entry
which calls `_dl_runtime_resolve` and fills in the GOT entry for subsequent
calls to the function.

The code sequences of the PLT entry for the default PLT style:
[,asm]
----
1: auipc t3, %pcrel_hi(function@.got.plt)
Expand All @@ -678,6 +710,15 @@ and fills in the GOT entry for subsequent calls to the function:
nop
----

The code sequences of the PLT entry for the the simple landing pad PLT style:
[,asm]
----
1: lpad 0
auipc t3, %pcrel_hi(function@.got.plt)
l[w|d] t3, %pcrel_lo(1b)(t3)
jalr t1, t3
----

==== Procedure Calls

`R_RISCV_CALL` and `R_RISCV_CALL_PLT` relocations are associated with
Expand Down Expand Up @@ -1361,6 +1402,58 @@ that a linker or runtime loader needs to check for compatibility.
The linker should ignore and discard unknown bits in program properties, and
issue warnings or errors.

<<rv-prog-prop-type>> provides details of the RISC-V ELF program property; the
meaning of each column is given below:


Name:: The name of the program property type, omitting the prefix of `GNU_PROPERTY_RISCV_`.

Value:: The type value for the program property type.

Size:: The data type size hold within this program property type.

Description:: Additional information about the program property type.


[[rv-prog-prop-type]]
.RISC-V-specific program property types
[cols="3,3,2,5"]
[width=100%]
|===
| Name | Value | Size | Description

kito-cheng marked this conversation as resolved.
Show resolved Hide resolved
| FEATURE_1_AND | 0xc0000000 | 4-bytes | RISC-V processor-specific features used in program.
|===

==== GNU_PROPERTY_RISCV_FEATURE_1_AND


`GNU_PROPERTY_RISCV_FEATURE_1_AND` describes a set of features, where each bit
represents a different feature. The linker should perform a bitwise AND
operation when merging different objects.

[%autowidth]
|===
| Bit | Bit Name
| 0 | GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED
| 1 | GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS
|===

`GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED` This bit indicate that all
executable sections are built to be compatible with the landing pad mechanism
provided by the `Zicfilp` extension. An executable or shared library with this
bit set is required to generate PLTs with the landing pad (`lpad`) instruction,
and all label are set to `0`.

`GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS`: This bit indicate that all executable
sections are built to be compatible with the shadow stack mechanism provided by
the `Zicfiss` extension. Loading an executable or shared library with this bit
set requires the execution environment to provide either the `Zicfiss` extension
or the `Zimop` extension. When the executable or shared library is compiled with
compressed instructions then loading an executable with this bit set requires
the execution environment to provide the `Zicfiss` extension or to provide both
the `Zcmop` and `Zimop` extensions.

=== Mapping Symbol

The section can have a mixture of code and data or code with different ISAs.
Expand Down
Loading