-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[RISCV][LLD] Zcmt RISC-V extension in lld #163142
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -43,6 +43,8 @@ class RISCV final : public TargetInfo { | |||||||||||||
| void scanSectionImpl(InputSectionBase &, Relocs<RelTy>); | ||||||||||||||
| template <class ELFT> void scanSection1(InputSectionBase &); | ||||||||||||||
| void scanSection(InputSectionBase &) override; | ||||||||||||||
| void writeTableJumpHeader(uint8_t *buf) const override; | ||||||||||||||
| void writeTableJumpEntry(uint8_t *buf, const uint64_t symbol) const override; | ||||||||||||||
| RelType getDynRel(RelType type) const override; | ||||||||||||||
| RelExpr getRelExpr(RelType type, const Symbol &s, | ||||||||||||||
| const uint8_t *loc) const override; | ||||||||||||||
|
|
@@ -75,6 +77,7 @@ class RISCV final : public TargetInfo { | |||||||||||||
| #define INTERNAL_R_RISCV_GPREL_S 257 | ||||||||||||||
| #define INTERNAL_R_RISCV_X0REL_I 258 | ||||||||||||||
| #define INTERNAL_R_RISCV_X0REL_S 259 | ||||||||||||||
| #define INTERNAL_R_RISCV_TBJAL 260 | ||||||||||||||
|
|
||||||||||||||
| const uint64_t dtpOffset = 0x800; | ||||||||||||||
|
|
||||||||||||||
|
|
@@ -274,6 +277,20 @@ void RISCV::writePlt(uint8_t *buf, const Symbol &sym, | |||||||||||||
| write32le(buf + 12, itype(ADDI, 0, 0, 0)); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| void RISCV::writeTableJumpHeader(uint8_t *buf) const { | ||||||||||||||
| if (ctx.arg.is64) | ||||||||||||||
| write64le(buf, ctx.mainPart->dynamic->getVA()); | ||||||||||||||
| else | ||||||||||||||
| write32le(buf, ctx.mainPart->dynamic->getVA()); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| void RISCV::writeTableJumpEntry(uint8_t *buf, const uint64_t address) const { | ||||||||||||||
| if (ctx.arg.is64) | ||||||||||||||
| write64le(buf, address); | ||||||||||||||
| else | ||||||||||||||
| write32le(buf, address); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| RelType RISCV::getDynRel(RelType type) const { | ||||||||||||||
| return type == ctx.target->symbolicRel ? type | ||||||||||||||
| : static_cast<RelType>(R_RISCV_NONE); | ||||||||||||||
|
|
@@ -496,6 +513,9 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { | |||||||||||||
| return; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| case INTERNAL_R_RISCV_TBJAL: | ||||||||||||||
| return; | ||||||||||||||
|
|
||||||||||||||
| case R_RISCV_ADD8: | ||||||||||||||
| *loc += val; | ||||||||||||||
| return; | ||||||||||||||
|
|
@@ -745,6 +765,32 @@ void elf::initSymbolAnchors(Ctx &ctx) { | |||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| static bool relaxTableJump(Ctx &ctx, const InputSection &sec, size_t i, | ||||||||||||||
| uint64_t loc, Relocation &r, uint32_t &remove) { | ||||||||||||||
| if (!ctx.in.riscvTableJumpSection || | ||||||||||||||
| !ctx.in.riscvTableJumpSection->isFinalized) | ||||||||||||||
| return false; | ||||||||||||||
|
|
||||||||||||||
| const uint32_t jalr = read32le(sec.contentMaybeDecompress().data() + | ||||||||||||||
| r.offset + (r.type == R_RISCV_JAL ? 0 : 4)); | ||||||||||||||
| const uint8_t rd = extractBits(jalr, 11, 7); | ||||||||||||||
| int tblEntryIndex = -1; | ||||||||||||||
| if (rd == X_X0) { | ||||||||||||||
| tblEntryIndex = ctx.in.riscvTableJumpSection->getCMJTEntryIndex(r.sym); | ||||||||||||||
| } else if (rd == X_RA) { | ||||||||||||||
| tblEntryIndex = ctx.in.riscvTableJumpSection->getCMJALTEntryIndex(r.sym); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| if (tblEntryIndex >= 0) { | ||||||||||||||
| sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_TBJAL; | ||||||||||||||
| sec.relaxAux->writes.push_back(0xA002 | | ||||||||||||||
| (tblEntryIndex << 2)); // cm.jt or cm.jalt | ||||||||||||||
| remove = (r.type == R_RISCV_JAL ? 2 : 6); | ||||||||||||||
| return true; | ||||||||||||||
| } | ||||||||||||||
| return false; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| // Relax R_RISCV_CALL/R_RISCV_CALL_PLT auipc+jalr to c.j, c.jal, or jal. | ||||||||||||||
| static void relaxCall(Ctx &ctx, const InputSection &sec, size_t i, uint64_t loc, | ||||||||||||||
| Relocation &r, uint32_t &remove) { | ||||||||||||||
|
|
@@ -767,6 +813,8 @@ static void relaxCall(Ctx &ctx, const InputSection &sec, size_t i, uint64_t loc, | |||||||||||||
| sec.relaxAux->relocTypes[i] = R_RISCV_RVC_JUMP; | ||||||||||||||
| sec.relaxAux->writes.push_back(0x2001); // c.jal | ||||||||||||||
| remove = 6; | ||||||||||||||
| } else if (remove >= 6 && relaxTableJump(ctx, sec, i, loc, r, remove)) { | ||||||||||||||
| // relaxTableJump sets remove | ||||||||||||||
| } else if (remove >= 4 && isInt<21>(displace)) { | ||||||||||||||
| sec.relaxAux->relocTypes[i] = R_RISCV_JAL; | ||||||||||||||
| sec.relaxAux->writes.push_back(0x6f | rd << 7); // jal | ||||||||||||||
|
|
@@ -890,6 +938,11 @@ static bool relax(Ctx &ctx, int pass, InputSection &sec) { | |||||||||||||
| relaxCall(ctx, sec, i, loc, r, remove); | ||||||||||||||
| } | ||||||||||||||
| break; | ||||||||||||||
| case R_RISCV_JAL: | ||||||||||||||
| if (relaxable(relocs, i)) { | ||||||||||||||
| relaxTableJump(ctx, sec, i, loc, r, remove); | ||||||||||||||
| } | ||||||||||||||
| break; | ||||||||||||||
| case R_RISCV_TPREL_HI20: | ||||||||||||||
| case R_RISCV_TPREL_ADD: | ||||||||||||||
| case R_RISCV_TPREL_LO12_I: | ||||||||||||||
|
|
@@ -1144,6 +1197,12 @@ void RISCV::finalizeRelax(int passes) const { | |||||||||||||
| case INTERNAL_R_RISCV_X0REL_I: | ||||||||||||||
| case INTERNAL_R_RISCV_X0REL_S: | ||||||||||||||
| break; | ||||||||||||||
| case INTERNAL_R_RISCV_TBJAL: | ||||||||||||||
| assert(ctx.arg.relaxTbljal); | ||||||||||||||
| assert((aux.writes[writesIdx] & 0xfc03) == 0xA002); | ||||||||||||||
| skip = 2; | ||||||||||||||
| write16le(p, aux.writes[writesIdx++]); | ||||||||||||||
| break; | ||||||||||||||
| case R_RISCV_RELAX: | ||||||||||||||
| // Used by relaxTlsLe to indicate the relocation is ignored. | ||||||||||||||
| break; | ||||||||||||||
|
|
@@ -1155,6 +1214,8 @@ void RISCV::finalizeRelax(int passes) const { | |||||||||||||
| skip = 4; | ||||||||||||||
| write32le(p, aux.writes[writesIdx++]); | ||||||||||||||
| break; | ||||||||||||||
| case R_RISCV_64: | ||||||||||||||
|
||||||||||||||
| case R_RISCV_64: | |
| case R_RISCV_64: | |
| // No action required for R_RISCV_64; present to suppress handling in relocateAlloc, | |
| // similar to R_RISCV_32, but no data needs to be written here. |
Copilot
AI
Nov 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Corrected grammar: 'didn't got' should be 'didn't get' or 'did not get'.
| warn("Table Jump Relaxation didn't got any reduction for code size."); | |
| warn("Table Jump Relaxation didn't get any reduction for code size."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| if (finalizedCMJALTEntries.size() > 0) { | |
| if (!finalizedCMJALTEntries.empty()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't the number of padding words be based startCMJALTEntryIdx - finalizedCMJTEntries.size()?
Copilot
AI
Nov 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The buffer offset calculation is incorrect. The loop should multiply i by ctx.arg.wordsize (either 8 for 64-bit or 4 for 32-bit). Currently buf + i only increments by single bytes instead of word-sized chunks, causing padding words to overlap and only the first byte of each word to be written.
| write64le(buf + i, 0); | |
| else | |
| write32le(buf + i, 0); | |
| write64le(buf + i * ctx.arg.wordsize, 0); | |
| else | |
| write32le(buf + i * ctx.arg.wordsize, 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, this does look weird.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SmallVectorImpl so we don't to repeat the size.
Can it be const reference?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should
remove >= 6be replaced with theremove >= (r.type == R_RISCV_JAL ? 2 : 6)? That matches the possible values relaxTableJump can set remove to.