-
Notifications
You must be signed in to change notification settings - Fork 163
/
riscv-elf.adoc
2010 lines (1593 loc) · 77.7 KB
/
riscv-elf.adoc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
[[riscv-elf]]
= RISC-V ELF Specification
ifeval::["{docname}" == "riscv-elf"]
include::prelude.adoc[]
endif::[]
== Code models
The RISC-V architecture constrains the addressing of positions in the
address space. There is no single instruction that can refer to an arbitrary
memory position using a literal as its argument. Rather, instructions exist
that, when combined together, can then be used to refer to a memory position
via its literal. And, when not, other data structures are used to help the
code to address the memory space. The coding conventions governing their use
are known as code models.
However, some code models can't access the whole address space. The linker may
raise an error if it cannot adjust the instructions to access the target address
in the current code model.
=== Medium low code model
The medium low code model, or `medlow`, allows the code to address the whole RV32
address space or the lower 2 GiB and highest 2 GiB of the RV64 address space
(`0xFFFFFFFF7FFFF800` ~ `0xFFFFFFFFFFFFFFFF` and `0x0` ~ `0x000000007FFFF7FF`).
By using the `lui` and load / store instructions, when referring to an object, or
`addi`, when calculating an address literal, for example,
a 32-bit address literal can be produced.
The following instructions show how to load a value, store a value, or calculate
an address in the `medlow` code model.
[,asm]
----
# Load value from a symbol
lui a0, %hi(symbol)
lw a0, %lo(symbol)(a0)
# Store value to a symbol
lui a0, %hi(symbol)
sw a1, %lo(symbol)(a0)
# Calculate address
lui a0, %hi(symbol)
addi a0, a0, %lo(symbol)
----
NOTE: The ranges on RV64 are not `0x0` ~ `0x000000007FFFFFFF` and
`0xFFFFFFFF80000000` ~ `0xFFFFFFFFFFFFFFFF` due to RISC-V's sign-extension of
immediates; the following code fragments show where the ranges come from:
[,asm]
----
# Largest postive number:
lui a0, 0x7ffff # a0 = 0x7ffff000
addi a0, 0x7ff # a0 = a0 + 2047 = 0x000000007FFFF7FF
# Smallest negative number:
lui a0, 0x80000 # a0 = 0xffffffff80000000
addi a0, a0, -0x800 # a0 = a0 + -2048 = 0xFFFFFFFF7FFFF800
----
=== Medium any code model
The medium any code model, or `medany`, allows the code to address the range
between -2 GiB and +2 GiB from its position. By using `auipc`
and load / store instructions, when referring to an object, or
`addi`, when calculating an address literal, for example,
a signed 32-bit offset, relative to the value of the `pc` register,
can be produced.
As a special edge-case, undefined weak symbols must still be supported, whose
addresses will be 0 and may be out of range depending on the address at which
the code is linked. Any references to possibly-undefined weak symbols should be
made indirectly through the GOT as is used for position-independent code. Not
doing so is deprecated and a future version of this specification will require
using the GOT, not just advise.
NOTE: This is not yet a requirement as existing toolchains predating this part
of the specification do not adhere to this, and without improvements to linker
relaxation support doing so would regress performance and code size.
The following instructions show how to load a value, store a value, or calculate
an address in the medany code model.
[,asm]
----
# Load value from a symbol
.Ltmp0: auipc a0, %pcrel_hi(symbol)
lw a0, %pcrel_lo(.Ltmp0)(a0)
# Store value to a symbol
.Ltmp1: auipc a0, %pcrel_hi(symbol)
sw a1, %pcrel_lo(.Ltmp1)(a0)
# Calculate address
.Ltmp2: auipc a0, %pcrel_hi(symbol)
addi a0, a0, %pcrel_lo(.Ltmp2)
----
NOTE: Although the generated code is technically position independent, it's not
suitable for ELF shared libraries due to differing symbol interposition rules;
for that, please use the medium position independent code model below.
=== Medium position independent code model
This model is similar to the medium any code model, but uses the
<<Global Offset Table,global offset table>> (GOT) for non-local symbol addresses.
[,asm]
----
# Load value from a local symbol
.Ltmp0: auipc a0, %pcrel_hi(symbol)
lw a0, %pcrel_lo(.Ltmp0)(a0)
# Store value to a local symbol
.Ltmp1: auipc a0, %pcrel_hi(symbol)
sw a1, %pcrel_lo(.Ltmp1)(a0)
# Calculate address of a local symbol
.Ltmp2: auipc a0, %pcrel_hi(symbol)
addi a0, a0, %pcrel_lo(.Ltmp2)
# Calculate address of non-local symbol
.Ltmp3: auipc a0, %got_pcrel_hi(symbol)
l[w|d] a0, a0, %pcrel_lo(.Ltmp3)
----
== Dynamic Linking
Any functions that use registers in a way that is incompatible with
the calling convention of the ABI in use must be annotated with
`STO_RISCV_VARIANT_CC`, as defined in <<Symbol Table>>.
NOTE: Vector registers have a variable size depending on the hardware
implementation and can be quite large. Saving/restoring all these vector
arguments in a run-time linker's lazy resolver would use a large amount of
stack space and hurt performance. `STO_RISCV_VARIANT_CC` attribute will require
the run-time linker to resolve the symbol directly to prevent saving/restoring
any vector registers.
== {Cpp} Name Mangling
{Cpp} name mangling for RISC-V follows
the _Itanium {Cpp} ABI_ <<itanium-cxx-abi>>;
plus mangling for RISC-V vector data types and vector mask types,
which are defined in the following section.
See the "Type encodings" section in _Itanium {Cpp} ABI_
for more detail on how to mangle types. Note that `__bf16` is mangled in the
same way as `std::bfloat16_t`.
=== Name Mangling for Vector Data Types, Vector Mask Types and Vector Tuple Types.
The vector data types and vector mask types, as defined in the section
<<Vector type sizes and alignments>>, are treated as vendor-extended types in
the _Itanium {Cpp} ABI_ <<itanium-cxx-abi>>. These mangled name for
these types is `"u"<len>"__rvv_"<type-name>`. Specifically,
prefixing the type name with `__rvv_`, which is prefixed by
a decimal string indicating its length, which is prefixed by "u".
For example:
[,c]
----
void foo(vint8m1_t x);
----
is mangled as
[,c]
----
_Z3foou15__rvv_vint8m1_t
----
[source,abnf]
----
mangled-name = "u" len "__rvv_" type-name
len = nonzero *DIGIT
nonzero = "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9"
type-name = identifier-nondigit *identifier-char
identifier-nondigit = ALPHA / "_"
identifier-char = identifier-nondigit / "_"
----
== ELF Object Files
The ELF object file format for RISC-V follows the
_Generic System V Application Binary Interface_ <<gabi>>
("gABI"); this specification only describes RISC-V-specific definitions.
=== File Header
The section below lists the defined RISC-V-specific values for several ELF
header fields; any fields not listed in this section have no RISC-V-specific
values.
e_ident::
EI_CLASS::: Specifies the base ISA, either RV32 or RV64.
Linking RV32 and RV64 code together is not supported.
+
--
[horizontal]
[[ELFCLASS64]]
ELFCLASS64:::: ELF-64 Object File
[horizontal]
[[ELFCLASS32]]
ELFCLASS32:::: ELF-32 Object File
--
EI_DATA::: Specifies the endianness; either big-endian or little-endian.
Linking big-endian and little-endian code together is not supported.
+
--
[horizontal]
ELFDATA2LSB:::: Little-endian Object File
ELFDATA2MSB:::: Big-endian Object File
--
e_machine:: Identifies the machine this ELF file targets. Always contains
EM_RISCV (243) for RISC-V ELF files.
e_flags:: Describes the format of this ELF file. These flags are used by the
linker to disallow linking ELF files with incompatible ABIs together,
<<e-flags-layout>> shows the layout of e_flags, and flag details are listed
below.
+
[[e-flags-layout]]
.Layout of e_flags
[cols="1,2,1,1,3,5"]
[width=80%]
|===
| Bit 0 | Bits 1 - 2 | Bit 3 | Bit 4 | Bits 5 - 23 | Bits 24 - 31
| RVC | Float ABI | RVE | TSO | *Reserved* | *Non-standard extensions*
|===
+
--
EF_RISCV_RVC (0x0001)::: This bit is set when the binary targets the C ABI,
which allows instructions to be aligned to 16-bit boundaries (the base RV32
and RV64 ISAs only allow 32-bit instruction alignment). When linking
objects which specify EF_RISCV_RVC, the linker is permitted to use RVC
instructions such as C.JAL in the linker relaxation process.
EF_RISCV_FLOAT_ABI_SOFT (0x0000):::
[[EF_RISCV_FLOAT_ABI_SOFT]]
EF_RISCV_FLOAT_ABI_SINGLE (0x0002):::
[[EF_RISCV_FLOAT_ABI_SINGLE]]
EF_RISCV_FLOAT_ABI_DOUBLE (0x0004):::
[[EF_RISCV_FLOAT_ABI_DOUBLE]]
EF_RISCV_FLOAT_ABI_QUAD (0x0006):::
[[EF_RISCV_FLOAT_ABI_QUAD]] These flags identify the floating point
ABI in use for this ELF file. They store the largest floating-point type
that ends up in registers as part of the ABI (but do not control if code
generation is allowed to use floating-point internally). The rule is that
if you have a floating-point type in a register, then you also have all
smaller floating-point types in registers. For example _DOUBLE would
store "float" and "double" values in F registers, but would not store "long
double" values in F registers. If none of the float ABI flags are set, the
object is taken to use the soft-float ABI.
EF_RISCV_FLOAT_ABI (0x0006)::: This macro is used as a mask to test for one
of the above floating-point ABIs, e.g.,
`(e_flags & EF_RISCV_FLOAT_ABI) == EF_RISCV_FLOAT_ABI_DOUBLE`.
[[EF_RISCV_RVE]]
EF_RISCV_RVE (0x0008)::: This bit is set when the binary targets the E ABI.
EF_RISCV_TSO (0x0010)::: This bit is set when the binary requires the RVTSO
memory consistency model.
Until such a time that the *Reserved* bits (0x00ffffe0) are allocated by future
versions of this specification, they shall not be set by standard software.
Non-standard extensions are free to use bits 24-31 for any purpose. This may
conflict with other non-standard extensions.
NOTE: There is no provision for compatibility between conflicting uses of the
e_flags bits reserved for non-standard extensions, and many standard RISC-V
tools will ignore them. Do not use them unless you control both the toolchain
and the operating system, and the ABI differences are so significant they
cannot be done with a .RISCV.attributes tag nor an ELF note, such as using a
different syscall ABI.
==== Policy for Merge Objects With Different File Headers
This section describe the behavior when the inputs files come with different
file headers.
`e_ident` and `e_machine` should have exact same value otherwise linker should
raise an error.
`e_flags` has different different policy for different fields:
RVC::: Input file could have different values for the RVC field; the linker
should set this field into EF_RISCV_RVC if any of the input objects has
been set.
Float ABI::: Linker should report errors if object files of different value
for float ABI field.
RVE::: Linker should report errors if object files of different value
for RVE field.
TSO::: Input files can have different values for the TSO field; the linker
should set this field if any of the input objects have the TSO field set.
NOTE: The static linker may ignore the compatibility checks if all fields in the
`e_flags` are zero and all sections in the input file are non-executable
sections.
--
=== String Tables
There are no RISC-V specific definitions relating to ELF string tables.
=== Symbol Table
st_other:: The lower 2 bits are used to specify a symbol's visibility. The
remaining 6 bits have no defined meaning in the ELF gABI. We use the highest
bit to mark functions that do not follow the standard calling convention for
the ABI in use.
+
The defined processor-specific `st_other` flags are listed in <<rv-st-other>>.
+
[[rv-st-other]]
.RISC-V-specific `st_other` flags
[cols="3,1"]
[width=60%]
|===
| Name | Mask
| STO_RISCV_VARIANT_CC | 0x80
|===
+
See <<Dynamic Linking>> for the meaning of `STO_RISCV_VARIANT_CC`.
`__global_pointer$` must be exported in the dynamic symbol table of dynamically-linked
executables if there are any GP-relative accesses present in the executable.
=== Relocations
RISC-V is a classical RISC architecture that has densely packed non-word
sized instruction immediate values. While the linker can make relocations on
arbitrary memory locations, many of the RISC-V relocations are designed for
use with specific instructions or instruction sequences. RISC-V has several
instruction specific encodings for PC-Relative address loading, jumps,
branches and the RVC compressed instruction set.
The purpose of this section is to describe the RISC-V specific instruction
sequences with their associated relocations in addition to the general purpose
machine word sized relocations that are used for symbol addresses in the
Global Offset Table or DWARF meta data.
<<reloc-table>> provides details of the RISC-V ELF relocations; the meaning of each
column is given below:
Enum:: The number of the relocation, encoded in the r_info field
ELF Reloc Type:: The name of the relocation, omitting the prefix of `R_RISCV_`.
Type:: Whether the relocation is a static or dynamic relocation:
+
- A static relocation relocates a location in a relocatable file, processed by a static linker.
- A dynamic relocation relocates a location in an executable or shared object, processed by a run-time linker.
- `Both`: Some relocation types are used by both static relocations and dynamic relocations.
Field:: Describes the set of bits affected by this relocation; see <<Field Symbols>> for the definitions of the individual types
Calculation:: Formula for how to resolve the relocation value; definitions of the
symbols can be found in <<Calculation Symbols>>
Description:: Additional information about the relocation
[[reloc-table]]
.Relocation types
[cols=">2,6,3,6,11"]
[width=100%]
|===
| Enum | ELF Reloc Type | Type | Field / Calculation | Description
.2+| 0 .2+| NONE .2+| None | .2+|
<|
.2+| 1 .2+| 32 .2+| Both | _word32_ .2+| 32-bit relocation
<| S + A
.2+| 2 .2+| 64 .2+| Both | _word64_ .2+| 64-bit relocation
<| S + A
.2+| 3 .2+| RELATIVE .2+| Dynamic | _wordclass_ .2+| Adjust a link address (A) to its load address (B + A)
<| B + A
.2+| 4 .2+| COPY .2+| Dynamic | .2+| Must be in executable; not allowed in shared library
<|
.2+| 5 .2+| JUMP_SLOT .2+| Dynamic | _wordclass_ .2+| Indicates the symbol associated with a PLT entry
<| S
.2+| 6 .2+| TLS_DTPMOD32 .2+| Dynamic | _word32_ .2+|
<| TLSMODULE
.2+| 7 .2+| TLS_DTPMOD64 .2+| Dynamic | _word64_ .2+|
<| TLSMODULE
.2+| 8 .2+| TLS_DTPREL32 .2+| Dynamic | _word32_ .2+|
<| S + A - TLS_DTV_OFFSET
.2+| 9 .2+| TLS_DTPREL64 .2+| Dynamic | _word64_ .2+|
<| S + A - TLS_DTV_OFFSET
.2+| 10 .2+| TLS_TPREL32 .2+| Dynamic | _word32_ .2+|
<| S + A + TLSOFFSET
.2+| 11 .2+| TLS_TPREL64 .2+| Dynamic | _word64_ .2+|
<| S + A + TLSOFFSET
.2+| 12 .2+| TLSDESC .2+| Dynamic | See <<TLS Descriptors>> .2+|
<| TLSDESC(S+A)
.2+| 16 .2+| BRANCH .2+| Static | _B-Type_ .2+| 12-bit PC-relative branch offset
<| S + A - P
.2+| 17 .2+| JAL .2+| Static | _J-Type_ .2+| 20-bit PC-relative jump offset
<| S + A - P
.2+| 18 .2+| CALL .2+| Static | _U+I-Type_ .2+| *Deprecated, please use CALL_PLT instead* 32-bit PC-relative function call, macros `call`, `tail`
<| S + A - P
.2+| 19 .2+| CALL_PLT .2+| Static | _U+I-Type_ .2+| 32-bit PC-relative function call, macros `call`, `tail` (PIC)
<| S + A - P
.2+| 20 .2+| GOT_HI20 .2+| Static | _U-Type_ .2+| High 20 bits of 32-bit PC-relative GOT access, `%got_pcrel_hi(symbol)`
<| G + GOT + A - P
.2+| 21 .2+| TLS_GOT_HI20 .2+| Static | _U-Type_ .2+| High 20 bits of 32-bit PC-relative TLS IE GOT access, macro `la.tls.ie`
<|
.2+| 22 .2+| TLS_GD_HI20 .2+| Static | _U-Type_ .2+| High 20 bits of 32-bit PC-relative TLS GD GOT reference, macro `la.tls.gd`
<|
.2+| 23 .2+| PCREL_HI20 .2+| Static | _U-Type_ .2+| High 20 bits of 32-bit PC-relative reference, `%pcrel_hi(symbol)`
<| S + A - P
.2+| 24 .2+| PCREL_LO12_I .2+| Static | _I-type_ .2+| Low 12 bits of a 32-bit PC-relative, `%pcrel_lo(address of %pcrel_hi)`, the addend must be 0
<| S - P
.2+| 25 .2+| PCREL_LO12_S .2+| Static | _S-Type_ .2+| Low 12 bits of a 32-bit PC-relative, `%pcrel_lo(address of %pcrel_hi)`, the addend must be 0
<| S - P
.2+| 26 .2+| HI20 .2+| Static | _U-Type_ .2+| High 20 bits of 32-bit absolute address, `%hi(symbol)`
<| S + A
.2+| 27 .2+| LO12_I .2+| Static | _I-Type_ .2+| Low 12 bits of 32-bit absolute address, `%lo(symbol)`
<| S + A
.2+| 28 .2+| LO12_S .2+| Static | _S-Type_ .2+| Low 12 bits of 32-bit absolute address, `%lo(symbol)`
<| S + A
.2+| 29 .2+| TPREL_HI20 .2+| Static | _U-Type_ .2+| High 20 bits of TLS LE thread pointer offset, `%tprel_hi(symbol)`
<|
.2+| 30 .2+| TPREL_LO12_I .2+| Static | _I-Type_ .2+| Low 12 bits of TLS LE thread pointer offset, `%tprel_lo(symbol)`
<|
.2+| 31 .2+| TPREL_LO12_S .2+| Static | _S-Type_ .2+| Low 12 bits of TLS LE thread pointer offset, `%tprel_lo(symbol)`
<|
.2+| 32 .2+| TPREL_ADD .2+| Static | .2+| TLS LE thread pointer usage, `%tprel_add(symbol)`
<|
.2+| 33 .2+| ADD8 .2+| Static | _word8_ .2+| 8-bit label addition
<| V + S + A
.2+| 34 .2+| ADD16 .2+| Static | _word16_ .2+| 16-bit label addition
<| V + S + A
.2+| 35 .2+| ADD32 .2+| Static | _word32_ .2+| 32-bit label addition
<| V + S + A
.2+| 36 .2+| ADD64 .2+| Static | _word64_ .2+| 64-bit label addition
<| V + S + A
.2+| 37 .2+| SUB8 .2+| Static | _word8_ .2+| 8-bit label subtraction
<| V - S - A
.2+| 38 .2+| SUB16 .2+| Static | _word16_ .2+| 16-bit label subtraction
<| V - S - A
.2+| 39 .2+| SUB32 .2+| Static | _word32_ .2+| 32-bit label subtraction
<| V - S - A
.2+| 40 .2+| SUB64 .2+| Static | _word64_ .2+| 64-bit label subtraction
<| V - S - A
.2+| 41 .2+| GOT32_PCREL .2+| Static | _word32_ .2+| 32-bit difference between the GOT entry for a symbol and the current location
<| G + GOT + A - P
.2+| 42 .2+| *Reserved* .2+| - | .2+| Reserved for future standard use
<|
.2+| 43 .2+| ALIGN .2+| Static | .2+| Alignment statement. The addend indicates the number of bytes occupied by `nop` instructions at the relocation offset. The alignment boundary is specified by the addend rounded up to the next power of two.
<|
.2+| 44 .2+| RVC_BRANCH .2+| Static | _CB-Type_ .2+| 8-bit PC-relative branch offset
<| S + A - P
.2+| 45 .2+| RVC_JUMP .2+| Static | _CJ-Type_ .2+| 11-bit PC-relative jump offset
<| S + A - P
.2+| 46-50 .2+| *Reserved* .2+| - | .2+| Reserved for future standard use
<|
.2+| 51 .2+| RELAX .2+| Static | .2+| Instruction can be relaxed, paired with a normal relocation at the same address
<|
.2+| 52 .2+| SUB6 .2+| Static | _word6_ .2+| Local label subtraction
<| V - S - A
.2+| 53 .2+| SET6 .2+| Static | _word6_ .2+| Local label assignment
<| S + A
.2+| 54 .2+| SET8 .2+| Static | _word8_ .2+| Local label assignment
<| S + A
.2+| 55 .2+| SET16 .2+| Static | _word16_ .2+| Local label assignment
<| S + A
.2+| 56 .2+| SET32 .2+| Static | _word32_ .2+| Local label assignment
<| S + A
.2+| 57 .2+| 32_PCREL .2+| Static | _word32_ .2+| 32-bit PC relative
<| S + A - P
.2+| 58 .2+| IRELATIVE .2+| Dynamic | _wordclass_ .2+| Relocation against a non-preemptible ifunc symbol
<| `ifunc_resolver(B + A)`
.2+| 59 .2+| PLT32 .2+| Static | _word32_ .2+| 32-bit relative offset to a function or its PLT entry
<| S + A - P
.2+| 60 .2+| SET_ULEB128 .2+| Static | _ULEB128_ .2+| Must be placed immediately before a SUB_ULEB128 with the same offset. Local label assignment <<uleb128-note,*note>>
<| S + A
.2+| 61 .2+| SUB_ULEB128 .2+| Static | _ULEB128_ .2+| Must be placed immediately after a SET_ULEB128 with the same offset. Local label subtraction <<uleb128-note,*note>>
<| V - S - A
.2+| 62 .2+| TLSDESC_HI20 .2+| Static | _U-Type_ .2+| High 20 bits of a 32-bit PC-relative offset into a TLS descriptor entry, `%tlsdesc_hi(symbol)`
<| S + A - P
.2+| 63 .2+| TLSDESC_LOAD_LO12 .2+| Static | _I-Type_ .2+| Low 12 bits of a 32-bit PC-relative offset into a TLS descriptor entry, `%tlsdesc_load_lo(address of %tlsdesc_hi)`, the addend must be 0
<| S - P
.2+| 64 .2+| TLSDESC_ADD_LO12 .2+| Static | _I-Type_ .2+| Low 12 bits of a 32-bit PC-relative offset into a TLS descriptor entry, `%tlsdesc_add_lo(address of %tlsdesc_hi)`, the addend must be 0
<| S - P
.2+| 65 .2+| TLSDESC_CALL .2+| Static | .2+| Annotate call to TLS descriptor resolver function, `%tlsdesc_call(address of %tlsdesc_hi)`, for relaxation purposes only
<|
.2+| 66-191 .2+| *Reserved* .2+| - | .2+| Reserved for future standard use
<|
.2+| 192-255 .2+| *Reserved* .2+| - | .2+| Reserved for nonstandard ABI extensions
<|
|===
Nonstandard extensions are free to use relocation numbers 192-255 for any
purpose. These relocations may conflict with other nonstandard extensions.
This section and later ones contain fragments written in assembler. The precise
assembler syntax, including that of the relocations, is described in the
_RISC-V Assembly Programmer's Manual_ <<rv-asm>>.
[[uleb128-note]]
NOTE: The assembler must allocate sufficient space to accommodate the final
value for the `R_RISCV_SET_ULEB128` and `R_RISCV_SUB_ULEB128` relocation pair
and fill the space with a single ULEB128-encoded value.
This is achieved by prepending the redundant `0x80` byte as necessary.
The linker must not alter the length of the ULEB128-encoded value.
==== Calculation Symbols
<<var-reloc-calc>> provides details on the variables used in relocation
calculation:
[[var-reloc-calc]]
.Variables used in relocation calculation
[%autowidth]
|===
| Variable | Description
| A | Addend field in the relocation entry associated with the symbol
| B | Base address of a shared object loaded into memory
| G | Offset of the symbol into the GOT (Global Offset Table)
| GOT | Address of the GOT (Global Offset Table)
| P | Position of the relocation
| S | Value of the symbol in the symbol table
| V | Value at the position of the relocation
| GP | Value of `__global_pointer$` symbol
| TLSMODULE | TLS module index for the object containing the symbol
| TLSOFFSET | TLS static block offset (relative to `tp`) for the object containing the symbol
|===
**Global Pointer**: It is assumed that program startup code will load the value
of the `__global_pointer$` symbol into register `gp` (aka `x3`).
==== Field Symbols
<<var-reloc-field>> provides details on the variables used in relocation fields:
[[var-reloc-field]]
.Variables used in relocation fields
[%autowidth]
|===
| Variable | Description
| _word6_ | Specifies the 6 least significant bits of a _word8_ field
| _word8_ | Specifies an 8-bit word
| _word16_ | Specifies a 16-bit word
| _word32_ | Specifies a 32-bit word
| _word64_ | Specifies a 64-bit word
| _ULEB128_ | Specifies a variable-length data encoded in ULEB128 format.
| _wordclass_ | Specifies a _word32_ field for ILP32 or a _word64_ field for LP64
| _B-Type_ | Specifies a field as the immediate field in a B-type instruction
| _CB-Type_ | Specifies a field as the immediate field in a CB-type instruction
| _CI-Type_ | Specifies a field as the immediate field in a CI-type instruction
| _CJ-Type_ | Specifies a field as the immediate field in a CJ-type instruction
| _I-Type_ | Specifies a field as the immediate field in an I-type instruction
| _S-Type_ | Specifies a field as the immediate field in an S-type instruction
| _U-Type_ | Specifies a field as the immediate field in an U-type instruction
| _J-Type_ | Specifies a field as the immediate field in a J-type instruction
| _U+I-Type_ | Specifies a field as the immediate fields in a U-type and I-type instruction pair
|===
==== Constants
<<const-reloc-field>> provides details on the constants used in relocation fields:
[[const-reloc-field]]
.Constants used in relocation fields
[cols="3,1"]
[width=30%]
|===
| Name | Value
| TLS_DTV_OFFSET | 0x800
|===
==== Absolute Addresses
32-bit absolute addresses in position dependent code are loaded with a pair
of instructions which have an associated pair of relocations:
`R_RISCV_HI20` plus `R_RISCV_LO12_I` or `R_RISCV_LO12_S`.
The `R_RISCV_HI20` refers to an `LUI` instruction containing the high
20-bits to be relocated to an absolute symbol address. The `LUI` instruction
is used in conjunction with one or more I-Type instructions (add immediate or
load) with `R_RISCV_LO12_I` relocations or S-Type instructions (store) with
`R_RISCV_LO12_S` relocations.
The addresses for pair of relocations are
calculated like this:
[horizontal]
HI20:: `(symbol_address + 0x800) >> 12`
LO12:: `symbol_address`
The following assembly and relocations show loading an absolute address:
[,asm]
----
lui a0, %hi(symbol) # R_RISCV_HI20 (symbol)
addi a0, a0, %lo(symbol) # R_RISCV_LO12_I (symbol)
----
A symbol can be loaded in multiple fragments using different addends, where
multiple instructions associated with `R_RISCV_LO12_I`/`R_RISCV_LO12_S` share a
single `R_RISCV_HI20`. The HI20 values for the multiple fragments must be
identical, a condition met when the symbol is sufficiently aligned.
[,asm]
----
lui a0, 0 # R_RISCV_HI20 (symbol)
lw a1, 0(a0) # R_RISCV_LO12_I (symbol)
lw a2, 0(a0) # R_RISCV_LO12_I (symbol+4)
lw a3, 0(a0) # R_RISCV_LO12_I (symbol+8)
lw a0, 0(a0) # R_RISCV_LO12_I (symbol+12)
----
==== Global Offset Table
For position independent code in dynamically linked objects, each shared
object contains a GOT (Global Offset Table), which contains addresses of
global symbols (objects and functions) referred to by the dynamically
linked shared object. The GOT in each shared library is filled in by the
dynamic linker during program loading, or on the first call to extern functions.
To avoid dynamic relocations within the text segment of position independent
code the GOT is used for indirection. Instead of code loading virtual addresses
directly, as can be done in static code, addresses are loaded from the GOT.
This allows runtime binding to external objects and functions at the expense of
a slightly higher runtime overhead for access to extern objects and functions.
==== Procedure Linkage Table
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).
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:
[,asm]
----
1: auipc t2, %pcrel_hi(.got.plt)
sub t1, t1, t3 # shifted .got.plt offset + hdr size + 12
l[w|d] t3, %pcrel_lo(1b)(t2) # _dl_runtime_resolve
addi t1, t1, -(hdr size + 12) # 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
----
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:
[,asm]
----
1: auipc t3, %pcrel_hi(function@.got.plt)
l[w|d] t3, %pcrel_lo(1b)(t3)
jalr t1, t3
nop
----
==== Procedure Calls
`R_RISCV_CALL` and `R_RISCV_CALL_PLT` relocations are associated with
pairs of instructions (`AUIPC+JALR`) generated by the `CALL` or `TAIL`
pseudoinstructions. Originally, these relocations had slightly different
behavior, but that has turned out to be unnecessary, and they are now
interchangeable, `R_RISCV_CALL` is deprecated, suggest using `R_RISCV_CALL_PLT`
instead.
With linker relaxation enabled, the `AUIPC` instruction in the `AUIPC+JALR` pair has
both a `R_RISCV_CALL` or `R_RISCV_CALL_PLT` relocation and an `R_RISCV_RELAX`
relocation indicating the instruction sequence can be relaxed during linking.
Procedure call linker relaxation allows the `AUIPC+JALR` pair to be relaxed
to the `JAL` instruction when the procedure or PLT entry is within (-1MiB to
+1MiB-2) of the instruction pair.
The pseudoinstruction:
[,asm]
----
call symbol
call symbol@plt
----
expands to the following assembly and relocation:
[,asm]
----
auipc ra, 0 # R_RISCV_CALL (symbol), R_RISCV_RELAX (symbol)
jalr ra, ra, 0
----
and when symbol has an `@plt` suffix it expands to:
[,asm]
----
auipc ra, 0 # R_RISCV_CALL_PLT (symbol), R_RISCV_RELAX (symbol)
jalr ra, ra, 0
----
==== PC-Relative Jumps and Branches
Unconditional jump (J-Type) instructions have a `R_RISCV_JAL` relocation
that can represent an even signed 21-bit offset (-1MiB to +1MiB-2).
Branch (SB-Type) instructions have a `R_RISCV_BRANCH` relocation that
can represent an even signed 13-bit offset (-4096 to +4094).
==== PC-Relative Symbol Addresses
32-bit PC-relative relocations for symbol addresses on sequences of
instructions such as the `AUIPC+ADDI` instruction pair expanded from
the `la` pseudoinstruction, in position independent code typically
have an associated pair of relocations: `R_RISCV_PCREL_HI20` plus
`R_RISCV_PCREL_LO12_I` or `R_RISCV_PCREL_LO12_S`.
The `R_RISCV_PCREL_HI20` relocation refers to an `AUIPC` instruction
containing the high 20-bits to be relocated to a symbol relative to the
program counter address of the `AUIPC` instruction. The `AUIPC`
instruction is used in conjunction with one or more I-Type instructions
(add immediate or load) with `R_RISCV_PCREL_LO12_I` relocations or S-Type
instructions (store) with `R_RISCV_PCREL_LO12_S` relocations.
The `R_RISCV_PCREL_LO12_I` or `R_RISCV_PCREL_LO12_S` relocations contain
a label pointing to an instruction in the same section with an
`R_RISCV_PCREL_HI20` relocation entry that points to the target symbol:
* At label: `R_RISCV_PCREL_HI20` relocation entry -> symbol
* `R_RISCV_PCREL_LO12_I` relocation entry -> label
To get the symbol address to perform the calculation to fill the 12-bit
immediate on the add, load or store instruction the linker finds the
`R_RISCV_PCREL_HI20` relocation entry associated with the `AUIPC`
instruction. The addresses for pair of relocations are calculated like this:
[horizontal]
HI20:: `(symbol_address - hi20_reloc_offset + 0x800) >> 12`
LO12:: `symbol_address - hi20_reloc_offset`
The successive instruction has a signed 12-bit immediate so the value of the
preceding high 20-bit relocation may have 1 added to it.
Note the compiler emitted instructions for PC-relative symbol addresses are
not necessarily sequential or in pairs. There is a constraint is that the
instruction with the `R_RISCV_PCREL_LO12_I` or `R_RISCV_PCREL_LO12_S`
relocation label points to a valid HI20 PC-relative relocation pointing to
the symbol.
Here is example assembler showing the relocation types:
[,asm]
----
label:
auipc t0, %pcrel_hi(symbol) # R_RISCV_PCREL_HI20 (symbol)
lui t1, 1
lw t2, t0, %pcrel_lo(label) # R_RISCV_PCREL_LO12_I (label)
add t2, t2, t1
sw t2, t0, %pcrel_lo(label) # R_RISCV_PCREL_LO12_S (label)
----
==== Relocation for Alignment
The relocation type `R_RISCV_ALIGN` marks a location that must be aligned to
`N`-bytes, where `N` is the smallest power of two that is greater than the value
of the addend field, e.g. `R_RISCV_ALIGN` with addend value 2 means align to 4
bytes, `R_RISCV_ALIGN` with addend value 4 means align to 8 bytes; this
relocation is only required if the containing section has any `R_RISCV_RELAX`
relocations, `R_RISCV_ALIGN` points to the beginning of the padding bytes,
and the instruction that actually needs to be aligned is located at the point
of `R_RISCV_ALIGN` plus its addend.
To ensure the linker can always satisfy the required alignment solely by
deleting bytes, the compiler or assembler must emit a `R_RISCV_ALIGN` relocation
and then insert `N` - <<IALIGN>> padding bytes before the location where we need to
align, it could be mark by an alignment directive like `.align`, `.p2align` or
`.balign` or emit by compiler directly, the addend value of that relocation
is the number of padding bytes.
The compiler and assembler must ensure padding bytes are valid instructions
without any side-effect like `nop` or `c.nop`, and make sure those instructions
are aligned to IALIGN if possible.
The linker may remove part of the padding bytes at the linking process to meet
the alignment requirement, and must make sure those padding bytes still are
valid instructions and each instruction is aligned to at least IALIGN byte.
Here is example to showing how `R_RISCV_ALIGN` is used:
[,asm]
----
0x0 c.nop # R_RISCV_ALIGN with addend 2
0x2 add t1, t2, t3 # This instruction must align to 4 byte.
----
NOTE: `R_RISCV_ALIGN` relocation is needed because linker relaxation can shrink
preceding code during the linking process, which may cause an aligned location
to become mis-aligned.
NOTE: IALIGN[[IALIGN]] means the instruction-address alignment constraint. IALIGN is 4
bytes in the base ISA, but some ISA extensions, including the compressed ISA
extension, relax IALIGN to 2 bytes. IALIGN may not take on any value other than
4 or 2. This term is also defined in `The RISC-V Instruction Set Manual` with a
similar meaning, the only difference being it is specified in terms of the number
of bits instead of the number of bytes.
NOTE: Here is pseudocode to decide the alignment of `R_RISCV_ALIGN` relocation:
[,python]
----
# input:
# addend: addend value of relocation with R_RISCV_ALIGN type.
# output:
# Alignment of this relocation.
def align(addend):
ALIGN = 1
while addend >= ALIGN:
ALIGN *= 2
return ALIGN
----
=== Thread Local Storage
RISC-V adopts the ELF Thread Local Storage Model in which ELF objects define
`.tbss` and `.tdata` sections and `PT_TLS` program headers that contain the
TLS "initialization images" for new threads. The `.tbss` and `.tdata` sections
are not referenced directly like regular segments, rather they are copied or
allocated to the thread local storage space of newly created threads.
See _ELF Handling For Thread-Local Storage_ <<tls>>.
In The ELF Thread Local Storage Model, TLS offsets are used instead of pointers.
The ELF TLS sections are initialization images for the thread local variables of
each new thread. A TLS offset defines an offset into the dynamic thread vector
which is pointed to by the TCB (Thread Control Block). RISC-V uses Variant I as
described by the ELF TLS specification, with `tp` containing the address one
past the end of the TCB.
There are various thread local storage models for statically allocated or
dynamically allocated thread local storage. <<tls-model>> lists the
thread local storage models:
[[tls-model]]
.TLS models
[cols="1,2"]
[width=70%]
|===
| Mnemonic | Model
| TLS LE | Local Exec
| TLS IE | Initial Exec
| TLS LD | Local Dynamic
| TLS GD | Global Dynamic
|===
The program linker in the case of static TLS or the dynamic linker in the case
of dynamic TLS allocate TLS offsets for storage of thread local variables.
NOTE: `Global Dynamic` model is also known as `General Dynamic` model.
==== Local Exec
Local exec is a form of static thread local storage. This model is used
when static linking as the TLS offsets are resolved during program linking.
Variable attribute:: `+__thread int i __attribute__((tls_model("local-exec")));+`
Example assembler load and store of a thread local variable `i` using the
`%tprel_hi`, `%tprel_add` and `%tprel_lo` assembler functions. The emitted
relocations are in comments.
[,asm]
----
lui a5,%tprel_hi(i) # R_RISCV_TPREL_HI20 (symbol)
add a5,a5,tp,%tprel_add(i) # R_RISCV_TPREL_ADD (symbol)
lw t0,%tprel_lo(i)(a5) # R_RISCV_TPREL_LO12_I (symbol)
addi t0,t0,1
sw t0,%tprel_lo(i)(a5) # R_RISCV_TPREL_LO12_S (symbol)
----
The `%tprel_add` assembler function does not return a value and is used purely
to associate the `R_RISCV_TPREL_ADD` relocation with the `add` instruction.
==== Initial Exec
Initial exec is is a form of static thread local storage that can be used in
shared libraries that use thread local storage. TLS relocations are performed
at load time. `dlopen` calls to libraries that use thread local storage may fail
when using the initial exec thread local storage model as TLS offsets must all
be resolved at load time. This model uses the GOT to resolve TLS offsets.
Variable attribute:: `+__thread int i __attribute__((tls_model("initial-exec")));+`
ELF flags:: DF_STATIC_TLS
Example assembler load and store of a thread local variable `i` using the
`la.tls.ie` pseudoinstruction, with the emitted TLS relocations in comments:
[,asm]
----
la.tls.ie a5,i
add a5,a5,tp
lw t0,0(a5)
addi t0,t0,1
sw t0,0(a5)
----
The assembler pseudoinstruction:
[,asm]
----
la.tls.ie a5,symbol
----
expands to the following assembly instructions and relocations:
[,asm]
----
label:
auipc a5, 0 # R_RISCV_TLS_GOT_HI20 (symbol)
{ld,lw} a5, 0(a5) # R_RISCV_PCREL_LO12_I (label)
----
==== Global Dynamic
RISC-V local dynamic and global dynamic TLS models generate equivalent object code.
The Global dynamic thread local storage model is used for PIC Shared libraries and
handles the case where more than one library uses thread local variables, and
additionally allows libraries to be loaded and unloaded at runtime using `dlopen`.
In the global dynamic model, application code calls the dynamic linker function
`__tls_get_addr` to locate TLS offsets into the dynamic thread vector at runtime.
Variable attribute:: `+__thread int i __attribute__((tls_model("global-dynamic")));+`
Example assembler load and store of a thread local variable `i` using the
`la.tls.gd` pseudoinstruction, with the emitted TLS relocations in comments:
[,asm]
----
la.tls.gd a0,i
call __tls_get_addr@plt
mv a5,a0
lw t0,0(a5)
addi t0,t0,1
sw t0,0(a5)
----
The assembler pseudoinstruction:
[,asm]
----
la.tls.gd a0,symbol
----
expands to the following assembly instructions and relocations:
[,asm]
----
label:
auipc a0,0 # R_RISCV_TLS_GD_HI20 (symbol)
addi a0,a0,0 # R_RISCV_PCREL_LO12_I (label)
----
In the Global Dynamic model, the runtime library provides the `__tls_get_addr` function:
[,c]
----
extern void *__tls_get_addr (tls_index *ti);
----
where the type tls_index is defined as:
[,c]
----
typedef struct
{
unsigned long int ti_module;
unsigned long int ti_offset;
} tls_index;
----