Difference between revisions of "NaplesPU LLD Linker"
(→linker) |
|||
(13 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
− | + | LLD is the LLVM proprietary linker. It is based on the GNU linker, and it is compatible to it in terms of arguments accepted. It also fully supports the ''ELF'' generation but also, in a progressive lower percentage, ''PE/COFF'', ''Mach-O'', ''WebAssembly'' and custom linker-scripts. | |
− | + | LLD is built as a set of libraries to join the main idea of the software modular design. | |
− | |||
− | |||
− | + | The NaplesPU implementation of LLD is made on an ELF-based approach, by adding a new Target class inside lld/ELF/Arch folder. [[NaplesPU.cpp]] contains the ''relocation'' logic and other information needed to support NaplesPU. Each NaplesPU application must be linked together with two additional object files: | |
− | + | * ''crt0.o'', is the object file resulting of the compilation of the start routine for the custom platform, composed of operations needed to set-up the platform. | |
− | + | * ''vectors.o'', is the Interrupt Vector Table. | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | == | + | == Relocations == |
− | + | This section explains how the relocations are implemented in NaplesPU. | |
− | + | All relocations are specified in the ''relocateOne'' method implementation. By looking at the target ISA, LLD must check for each instruction type in which an immediate value is specified to verify if it can fit the machine instruction field. | |
− | <syntaxhighlight | + | <syntaxhighlight> |
− | + | void NaplesPU::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { | |
− | + | int64_t Offset; | |
− | + | switch (Type) { | |
+ | default: | ||
+ | fatal("unrecognized reloc " + Twine(Type)); | ||
+ | case R_NUPLUS_ABS32: | ||
+ | write32le(Loc, Val); | ||
+ | break; | ||
+ | case R_NUPLUS_BRANCH: | ||
+ | //Check Offset for J-Type Instructions | ||
+ | checkInt(Loc, Val, 18, Type); | ||
+ | applyNaplesPUReloc<18, 0>(Loc, Type, Val); | ||
+ | break; | ||
+ | case R_NUPLUS_PCREL_MEM: | ||
+ | //Check Offset for M-Type Instructions | ||
+ | checkInt(Loc, Val, 9, Type); | ||
+ | applyNaplesPUReloc<9, 3>(Loc, Type, Val); | ||
+ | break; | ||
+ | case R_NUPLUS_PCREL_LEA: | ||
+ | //Check Offset for I-Type Instructions | ||
+ | checkInt(Loc, Val, 9, Type); | ||
+ | applyNaplesPUReloc<9, 3>(Loc, Type, Val); | ||
+ | break; | ||
+ | case R_NUPLUS_ABS_HIGH_LEA: | ||
+ | //Check Offset for MOVEI-Type Instructions | ||
+ | checkInt(Loc, (Val >> 16) & 0xFFFF , 16, Type); | ||
+ | applyNaplesPUReloc<16, 2>(Loc, Type, (Val >> 16) & 0xFFFF); | ||
+ | break; | ||
+ | case R_NUPLUS_ABS_LOW_LEA: | ||
+ | //Check Offset for MOVEI-Type Instructions | ||
+ | checkInt(Loc, (Val) & 0xFFFF , 16, Type); | ||
+ | applyNaplesPUReloc<16, 2>(Loc, Type, (Val) & 0xFFFF); | ||
+ | break; | ||
+ | } | ||
+ | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | + | All of these implemented relocations relies on the method ''applyNaplesPURelocation'' that simply writes back the value into the instruction. | |
− | |||
− | |||
− | |||
− | + | == Linkerscript == | |
− | + | All memory images generated for NaplesPU must be linked in a proper way. This way is specified by the linkerscript: | |
− | |||
− | + | <syntaxhighlight> | |
− | + | stacks_dim = 16K; | |
− | |||
− | |||
− | <syntaxhighlight | ||
− | stacks_dim = | ||
stacks_base = 0x80000; | stacks_base = 0x80000; | ||
− | + | threads_per_core = 0x8; | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
SECTIONS | SECTIONS | ||
{ | { | ||
− | . = | + | . = 0x00000380; |
− | .text.vectors : { | + | .text.vectors : { |
+ | *vectors.o(.text) | ||
+ | . = 0x00000400; | ||
+ | } | ||
− | .text.start : { | + | .text.start : { |
+ | *crt0.o(.text) | ||
+ | } | ||
.text : { *(.text) } | .text : { *(.text) } | ||
+ | . = 0x00800000; | ||
.data : { *(.data) } | .data : { *(.data) } | ||
− | + | ||
. = ALIGN(64); | . = ALIGN(64); | ||
scratchpad : { *(scratchpad) } | scratchpad : { *(scratchpad) } | ||
.bss : { *(.bss) } | .bss : { *(.bss) } | ||
+ | |||
+ | .eh_frame : { *(.eh_frame) } | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | + | As shown above, the linker script commonly defines where the sections must be placed into the memory. Also, it solves undefined symbols of the start routine, specifying the stack size per-thread, the number of threads and the starting address for the stack frame. | |
− | |||
− | |||
− | |||
− |
Latest revision as of 16:21, 21 June 2019
LLD is the LLVM proprietary linker. It is based on the GNU linker, and it is compatible to it in terms of arguments accepted. It also fully supports the ELF generation but also, in a progressive lower percentage, PE/COFF, Mach-O, WebAssembly and custom linker-scripts. LLD is built as a set of libraries to join the main idea of the software modular design.
The NaplesPU implementation of LLD is made on an ELF-based approach, by adding a new Target class inside lld/ELF/Arch folder. NaplesPU.cpp contains the relocation logic and other information needed to support NaplesPU. Each NaplesPU application must be linked together with two additional object files:
- crt0.o, is the object file resulting of the compilation of the start routine for the custom platform, composed of operations needed to set-up the platform.
- vectors.o, is the Interrupt Vector Table.
Relocations
This section explains how the relocations are implemented in NaplesPU. All relocations are specified in the relocateOne method implementation. By looking at the target ISA, LLD must check for each instruction type in which an immediate value is specified to verify if it can fit the machine instruction field.
void NaplesPU::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
int64_t Offset;
switch (Type) {
default:
fatal("unrecognized reloc " + Twine(Type));
case R_NUPLUS_ABS32:
write32le(Loc, Val);
break;
case R_NUPLUS_BRANCH:
//Check Offset for J-Type Instructions
checkInt(Loc, Val, 18, Type);
applyNaplesPUReloc<18, 0>(Loc, Type, Val);
break;
case R_NUPLUS_PCREL_MEM:
//Check Offset for M-Type Instructions
checkInt(Loc, Val, 9, Type);
applyNaplesPUReloc<9, 3>(Loc, Type, Val);
break;
case R_NUPLUS_PCREL_LEA:
//Check Offset for I-Type Instructions
checkInt(Loc, Val, 9, Type);
applyNaplesPUReloc<9, 3>(Loc, Type, Val);
break;
case R_NUPLUS_ABS_HIGH_LEA:
//Check Offset for MOVEI-Type Instructions
checkInt(Loc, (Val >> 16) & 0xFFFF , 16, Type);
applyNaplesPUReloc<16, 2>(Loc, Type, (Val >> 16) & 0xFFFF);
break;
case R_NUPLUS_ABS_LOW_LEA:
//Check Offset for MOVEI-Type Instructions
checkInt(Loc, (Val) & 0xFFFF , 16, Type);
applyNaplesPUReloc<16, 2>(Loc, Type, (Val) & 0xFFFF);
break;
}
}
All of these implemented relocations relies on the method applyNaplesPURelocation that simply writes back the value into the instruction.
Linkerscript
All memory images generated for NaplesPU must be linked in a proper way. This way is specified by the linkerscript:
stacks_dim = 16K;
stacks_base = 0x80000;
threads_per_core = 0x8;
SECTIONS
{
. = 0x00000380;
.text.vectors : {
*vectors.o(.text)
. = 0x00000400;
}
.text.start : {
*crt0.o(.text)
}
.text : { *(.text) }
. = 0x00800000;
.data : { *(.data) }
. = ALIGN(64);
scratchpad : { *(scratchpad) }
.bss : { *(.bss) }
.eh_frame : { *(.eh_frame) }
}
As shown above, the linker script commonly defines where the sections must be placed into the memory. Also, it solves undefined symbols of the start routine, specifying the stack size per-thread, the number of threads and the starting address for the stack frame.