Skip to content

[lld] More info for aarch64 ldr/str misaligning error #135004

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

GulinSS
Copy link

@GulinSS GulinSS commented Apr 9, 2025

It adds details to lld error message for aarch64 misalign mistakes.

The origin message:

ld.lld: error: misaligned ldr/str offset
ld.lld: error: misaligned ldr/str offset
ld.lld: error: misaligned ldr/str offset
ld.lld: error: misaligned ldr/str offset
ld.lld: error: misaligned ldr/str offset
ld.lld: error: misaligned ldr/str offset

Very non-informative. What is the cause? Who knows. How to debug it? No easy ways. 🩸 😔

The new message is:

ld.lld: error: misaligned ldr/str offset: 0x76c@f9400318 with align 2^3 from free@Signal.o
ld.lld: error: misaligned ldr/str offset: 0x574@f9400318 with align 2^3 from backtraceFree@Internal.o
ld.lld: error: misaligned ldr/str offset: 0x904@f9400252 with align 2^3 from enabled_capabilities@Sync.o
ld.lld: error: misaligned ldr/str offset: 0x904@f9400252 with align 2^3 from enabled_capabilities@Sync.o
ld.lld: error: misaligned ldr/str offset: 0x804@f9400252 with align 2^3 from rts_stop_on_exception@Exception.o
ld.lld: error: misaligned ldr/str offset: 0x804@f9400231 with align 2^3 from rts_stop_on_exception@Exception.o

Well, notable better. Now we know the instruction code, the actual offset and the reason of the relocation: object file + symbol name. Enough information to resolve any similar issues! :godmode: 💪

Without these changes it would be notable more painful to deal with this.

Co-authored-by: Kirill Andreev <hindmost.one@gmail.com>
Co-authored-by: Andrei Borzenkov <root@sandwitch.dev>
Co-authored-by: Dmitrii Egorov <egorov.d.i@icloud.com>
Co-authored-by: Danil Berestov <goosedb@yandex.ru>
Co-authored-by: Ilya Baryshnikov <zlonast3@gmail.com>
Copy link

github-actions bot commented Apr 9, 2025

Thank you for submitting a Pull Request (PR) to the LLVM Project!

This PR will be automatically labeled and the relevant teams will be notified.

If you wish to, you can add reviewers by using the "Reviewers" section on this page.

If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using @ followed by their GitHub username.

If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers.

If you have further questions, they may be answered by the LLVM GitHub User Guide.

You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums.

@llvmbot
Copy link
Member

llvmbot commented Apr 9, 2025

@llvm/pr-subscribers-platform-windows

@llvm/pr-subscribers-lld-coff

Author: Serge S. Gulin (GulinSS)

Changes

It adds details to lld error message for aarch64 misalign mistakes.

The origin message:

ld.lld: error: misaligned ldr/str offset
ld.lld: error: misaligned ldr/str offset
ld.lld: error: misaligned ldr/str offset
ld.lld: error: misaligned ldr/str offset
ld.lld: error: misaligned ldr/str offset
ld.lld: error: misaligned ldr/str offset

Very non-informative. What is the cause? Who knows. How to debug it? No easy ways. 🩸 😔

The new message is:

ld.lld: error: misaligned ldr/str offset: 0x76c@<!-- -->f9400318 with align 2^3 from free@<!-- -->Signal.o
ld.lld: error: misaligned ldr/str offset: 0x574@<!-- -->f9400318 with align 2^3 from backtraceFree@<!-- -->Internal.o
ld.lld: error: misaligned ldr/str offset: 0x904@<!-- -->f9400252 with align 2^3 from enabled_capabilities@<!-- -->Sync.o
ld.lld: error: misaligned ldr/str offset: 0x904@<!-- -->f9400252 with align 2^3 from enabled_capabilities@<!-- -->Sync.o
ld.lld: error: misaligned ldr/str offset: 0x804@<!-- -->f9400252 with align 2^3 from rts_stop_on_exception@<!-- -->Exception.o
ld.lld: error: misaligned ldr/str offset: 0x804@<!-- -->f9400231 with align 2^3 from rts_stop_on_exception@<!-- -->Exception.o

Well, notable better. Now we know the instruction code, the actual offset and the reason of the relocation: object file + symbol name. Enough information to resolve any similar issues! :godmode: 💪

Without these changes it would be notable more painful to deal with this.


Full diff: https://github.com/llvm/llvm-project/pull/135004.diff

2 Files Affected:

  • (modified) lld/COFF/Chunks.cpp (+31-12)
  • (modified) lld/COFF/Chunks.h (+1-1)
diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp
index 3494d1ba0ac02..90c33b52c4cbe 100644
--- a/lld/COFF/Chunks.cpp
+++ b/lld/COFF/Chunks.cpp
@@ -268,7 +268,7 @@ void applyArm64Imm(uint8_t *off, uint64_t imm, uint32_t rangeLimit) {
 // Even if larger loads/stores have a larger range, limit the
 // effective offset to 12 bit, since it is intended to be a
 // page offset.
-static void applyArm64Ldr(uint8_t *off, uint64_t imm) {
+static void applyArm64Ldr(const Twine &msg_location, uint8_t *off, uint64_t imm) {
   uint32_t orig = read32le(off);
   uint32_t size = orig >> 30;
   // 0x04000000 indicates SIMD/FP registers
@@ -276,7 +276,9 @@ static void applyArm64Ldr(uint8_t *off, uint64_t imm) {
   if ((orig & 0x4800000) == 0x4800000)
     size += 4;
   if ((imm & ((1 << size) - 1)) != 0)
-    error("misaligned ldr/str offset");
+    error(llvm::Twine {"misaligned ldr/str offset: 0x"} + llvm::Twine::utohexstr(imm)
+      + "@" + llvm::Twine::utohexstr(static_cast<uint64_t>(orig))
+      + " with align 2^" + llvm::Twine(size) + " from " + msg_location);
   applyArm64Imm(off, imm >> size, size);
 }
 
@@ -299,10 +301,10 @@ static void applySecRelHigh12A(const SectionChunk *sec, uint8_t *off,
   applyArm64Imm(off, secRel & 0xfff, 0);
 }
 
-static void applySecRelLdr(const SectionChunk *sec, uint8_t *off,
+static void applySecRelLdr(const SectionChunk *sec, const Twine &msg_location, uint8_t *off,
                            OutputSection *os, uint64_t s) {
   if (checkSecRel(sec, os))
-    applyArm64Ldr(off, (s - os->getRVA()) & 0xfff);
+    applyArm64Ldr(msg_location, off, (s - os->getRVA()) & 0xfff);
 }
 
 void applyArm64Branch26(uint8_t *off, int64_t v) {
@@ -323,14 +325,23 @@ static void applyArm64Branch14(uint8_t *off, int64_t v) {
   or32(off, (v & 0x0000FFFC) << 3);
 }
 
-void SectionChunk::applyRelARM64(uint8_t *off, uint16_t type, OutputSection *os,
+void SectionChunk::applyRelARM64(uint8_t *off, const coff_relocation &rel, OutputSection *os,
                                  uint64_t s, uint64_t p,
                                  uint64_t imageBase) const {
-  switch (type) {
+  // COPY FROM: maybeReportRelocationToDiscarded
+  StringRef sym_name;
+  if (this->sym) {
+    sym_name = this->sym->getName();
+  } else {
+    COFFSymbolRef coffSym = check(this->file->getCOFFObj()->getSymbol(rel.SymbolTableIndex));
+    sym_name = check(this->file->getCOFFObj()->getSymbolName(coffSym));
+  }
+
+  switch (rel.Type) {
   case IMAGE_REL_ARM64_PAGEBASE_REL21: applyArm64Addr(off, s, p, 12); break;
   case IMAGE_REL_ARM64_REL21:          applyArm64Addr(off, s, p, 0); break;
   case IMAGE_REL_ARM64_PAGEOFFSET_12A: applyArm64Imm(off, s & 0xfff, 0); break;
-  case IMAGE_REL_ARM64_PAGEOFFSET_12L: applyArm64Ldr(off, s & 0xfff); break;
+  case IMAGE_REL_ARM64_PAGEOFFSET_12L: applyArm64Ldr(sym_name + "@" + this->file->getName(), off, s & 0xfff); break;
   case IMAGE_REL_ARM64_BRANCH26:       applyArm64Branch26(off, s - p); break;
   case IMAGE_REL_ARM64_BRANCH19:       applyArm64Branch19(off, s - p); break;
   case IMAGE_REL_ARM64_BRANCH14:       applyArm64Branch14(off, s - p); break;
@@ -344,13 +355,13 @@ void SectionChunk::applyRelARM64(uint8_t *off, uint16_t type, OutputSection *os,
   case IMAGE_REL_ARM64_SECREL:         applySecRel(this, off, os, s); break;
   case IMAGE_REL_ARM64_SECREL_LOW12A:  applySecRelLow12A(this, off, os, s); break;
   case IMAGE_REL_ARM64_SECREL_HIGH12A: applySecRelHigh12A(this, off, os, s); break;
-  case IMAGE_REL_ARM64_SECREL_LOW12L:  applySecRelLdr(this, off, os, s); break;
+  case IMAGE_REL_ARM64_SECREL_LOW12L:  applySecRelLdr(this, sym_name + "@" + this->file->getName(), off, os, s); break;
   case IMAGE_REL_ARM64_SECTION:
     applySecIdx(off, os, file->symtab.ctx.outputSections.size());
     break;
   case IMAGE_REL_ARM64_REL32:          add32(off, s - p - 4); break;
   default:
-    error("unsupported relocation type 0x" + Twine::utohexstr(type) + " in " +
+    error("unsupported relocation type 0x" + Twine::utohexstr(rel.Type) + " in " +
           toString(file));
   }
 }
@@ -368,6 +379,7 @@ static void maybeReportRelocationToDiscarded(const SectionChunk *fromChunk,
 
   // Get the name of the symbol. If it's null, it was discarded early, so we
   // have to go back to the object file.
+  // COPY TO: SectionChunk::applyRelARM64.
   ObjFile *file = fromChunk->file;
   std::string name;
   if (sym) {
@@ -457,7 +469,7 @@ void SectionChunk::applyRelocation(uint8_t *off,
     applyRelARM(off, rel.Type, os, s, p, imageBase);
     break;
   case Triple::aarch64:
-    applyRelARM64(off, rel.Type, os, s, p, imageBase);
+    applyRelARM64(off, rel, os, s, p, imageBase);
     break;
   default:
     llvm_unreachable("unknown machine type");
@@ -829,10 +841,17 @@ void ImportThunkChunkARM::writeTo(uint8_t *buf) const {
 }
 
 void ImportThunkChunkARM64::writeTo(uint8_t *buf) const {
-  int64_t off = impSymbol->getRVA() & 0xfff;
   memcpy(buf, importThunkARM64, sizeof(importThunkARM64));
   applyArm64Addr(buf, impSymbol->getRVA(), rva, 12);
-  applyArm64Ldr(buf + 4, off);
+
+  StringRef fileName;
+  if (isa<DefinedImportData>(impSymbol))
+    fileName = static_cast<DefinedImportData *>(impSymbol)->getDLLName();
+  else
+    fileName = "<not_defined_import_data>";
+
+  int64_t off = impSymbol->getRVA() & 0xfff;
+  applyArm64Ldr(impSymbol->getName() + "@" + fileName, buf + 4, off);
 }
 
 // A Thumb2, PIC, non-interworking range extension thunk.
diff --git a/lld/COFF/Chunks.h b/lld/COFF/Chunks.h
index 9f68d5a325cc5..0e04f7b82cc20 100644
--- a/lld/COFF/Chunks.h
+++ b/lld/COFF/Chunks.h
@@ -280,7 +280,7 @@ class SectionChunk : public Chunk {
                    uint64_t p, uint64_t imageBase) const;
   void applyRelARM(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s,
                    uint64_t p, uint64_t imageBase) const;
-  void applyRelARM64(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s,
+  void applyRelARM64(uint8_t *off, const coff_relocation &rel, OutputSection *os, uint64_t s,
                      uint64_t p, uint64_t imageBase) const;
 
   void getRuntimePseudoRelocs(std::vector<RuntimePseudoReloc> &res);

@llvmbot
Copy link
Member

llvmbot commented Apr 9, 2025

@llvm/pr-subscribers-lld

Author: Serge S. Gulin (GulinSS)

Changes

It adds details to lld error message for aarch64 misalign mistakes.

The origin message:

ld.lld: error: misaligned ldr/str offset
ld.lld: error: misaligned ldr/str offset
ld.lld: error: misaligned ldr/str offset
ld.lld: error: misaligned ldr/str offset
ld.lld: error: misaligned ldr/str offset
ld.lld: error: misaligned ldr/str offset

Very non-informative. What is the cause? Who knows. How to debug it? No easy ways. 🩸 😔

The new message is:

ld.lld: error: misaligned ldr/str offset: 0x76c@<!-- -->f9400318 with align 2^3 from free@<!-- -->Signal.o
ld.lld: error: misaligned ldr/str offset: 0x574@<!-- -->f9400318 with align 2^3 from backtraceFree@<!-- -->Internal.o
ld.lld: error: misaligned ldr/str offset: 0x904@<!-- -->f9400252 with align 2^3 from enabled_capabilities@<!-- -->Sync.o
ld.lld: error: misaligned ldr/str offset: 0x904@<!-- -->f9400252 with align 2^3 from enabled_capabilities@<!-- -->Sync.o
ld.lld: error: misaligned ldr/str offset: 0x804@<!-- -->f9400252 with align 2^3 from rts_stop_on_exception@<!-- -->Exception.o
ld.lld: error: misaligned ldr/str offset: 0x804@<!-- -->f9400231 with align 2^3 from rts_stop_on_exception@<!-- -->Exception.o

Well, notable better. Now we know the instruction code, the actual offset and the reason of the relocation: object file + symbol name. Enough information to resolve any similar issues! :godmode: 💪

Without these changes it would be notable more painful to deal with this.


Full diff: https://github.com/llvm/llvm-project/pull/135004.diff

2 Files Affected:

  • (modified) lld/COFF/Chunks.cpp (+31-12)
  • (modified) lld/COFF/Chunks.h (+1-1)
diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp
index 3494d1ba0ac02..90c33b52c4cbe 100644
--- a/lld/COFF/Chunks.cpp
+++ b/lld/COFF/Chunks.cpp
@@ -268,7 +268,7 @@ void applyArm64Imm(uint8_t *off, uint64_t imm, uint32_t rangeLimit) {
 // Even if larger loads/stores have a larger range, limit the
 // effective offset to 12 bit, since it is intended to be a
 // page offset.
-static void applyArm64Ldr(uint8_t *off, uint64_t imm) {
+static void applyArm64Ldr(const Twine &msg_location, uint8_t *off, uint64_t imm) {
   uint32_t orig = read32le(off);
   uint32_t size = orig >> 30;
   // 0x04000000 indicates SIMD/FP registers
@@ -276,7 +276,9 @@ static void applyArm64Ldr(uint8_t *off, uint64_t imm) {
   if ((orig & 0x4800000) == 0x4800000)
     size += 4;
   if ((imm & ((1 << size) - 1)) != 0)
-    error("misaligned ldr/str offset");
+    error(llvm::Twine {"misaligned ldr/str offset: 0x"} + llvm::Twine::utohexstr(imm)
+      + "@" + llvm::Twine::utohexstr(static_cast<uint64_t>(orig))
+      + " with align 2^" + llvm::Twine(size) + " from " + msg_location);
   applyArm64Imm(off, imm >> size, size);
 }
 
@@ -299,10 +301,10 @@ static void applySecRelHigh12A(const SectionChunk *sec, uint8_t *off,
   applyArm64Imm(off, secRel & 0xfff, 0);
 }
 
-static void applySecRelLdr(const SectionChunk *sec, uint8_t *off,
+static void applySecRelLdr(const SectionChunk *sec, const Twine &msg_location, uint8_t *off,
                            OutputSection *os, uint64_t s) {
   if (checkSecRel(sec, os))
-    applyArm64Ldr(off, (s - os->getRVA()) & 0xfff);
+    applyArm64Ldr(msg_location, off, (s - os->getRVA()) & 0xfff);
 }
 
 void applyArm64Branch26(uint8_t *off, int64_t v) {
@@ -323,14 +325,23 @@ static void applyArm64Branch14(uint8_t *off, int64_t v) {
   or32(off, (v & 0x0000FFFC) << 3);
 }
 
-void SectionChunk::applyRelARM64(uint8_t *off, uint16_t type, OutputSection *os,
+void SectionChunk::applyRelARM64(uint8_t *off, const coff_relocation &rel, OutputSection *os,
                                  uint64_t s, uint64_t p,
                                  uint64_t imageBase) const {
-  switch (type) {
+  // COPY FROM: maybeReportRelocationToDiscarded
+  StringRef sym_name;
+  if (this->sym) {
+    sym_name = this->sym->getName();
+  } else {
+    COFFSymbolRef coffSym = check(this->file->getCOFFObj()->getSymbol(rel.SymbolTableIndex));
+    sym_name = check(this->file->getCOFFObj()->getSymbolName(coffSym));
+  }
+
+  switch (rel.Type) {
   case IMAGE_REL_ARM64_PAGEBASE_REL21: applyArm64Addr(off, s, p, 12); break;
   case IMAGE_REL_ARM64_REL21:          applyArm64Addr(off, s, p, 0); break;
   case IMAGE_REL_ARM64_PAGEOFFSET_12A: applyArm64Imm(off, s & 0xfff, 0); break;
-  case IMAGE_REL_ARM64_PAGEOFFSET_12L: applyArm64Ldr(off, s & 0xfff); break;
+  case IMAGE_REL_ARM64_PAGEOFFSET_12L: applyArm64Ldr(sym_name + "@" + this->file->getName(), off, s & 0xfff); break;
   case IMAGE_REL_ARM64_BRANCH26:       applyArm64Branch26(off, s - p); break;
   case IMAGE_REL_ARM64_BRANCH19:       applyArm64Branch19(off, s - p); break;
   case IMAGE_REL_ARM64_BRANCH14:       applyArm64Branch14(off, s - p); break;
@@ -344,13 +355,13 @@ void SectionChunk::applyRelARM64(uint8_t *off, uint16_t type, OutputSection *os,
   case IMAGE_REL_ARM64_SECREL:         applySecRel(this, off, os, s); break;
   case IMAGE_REL_ARM64_SECREL_LOW12A:  applySecRelLow12A(this, off, os, s); break;
   case IMAGE_REL_ARM64_SECREL_HIGH12A: applySecRelHigh12A(this, off, os, s); break;
-  case IMAGE_REL_ARM64_SECREL_LOW12L:  applySecRelLdr(this, off, os, s); break;
+  case IMAGE_REL_ARM64_SECREL_LOW12L:  applySecRelLdr(this, sym_name + "@" + this->file->getName(), off, os, s); break;
   case IMAGE_REL_ARM64_SECTION:
     applySecIdx(off, os, file->symtab.ctx.outputSections.size());
     break;
   case IMAGE_REL_ARM64_REL32:          add32(off, s - p - 4); break;
   default:
-    error("unsupported relocation type 0x" + Twine::utohexstr(type) + " in " +
+    error("unsupported relocation type 0x" + Twine::utohexstr(rel.Type) + " in " +
           toString(file));
   }
 }
@@ -368,6 +379,7 @@ static void maybeReportRelocationToDiscarded(const SectionChunk *fromChunk,
 
   // Get the name of the symbol. If it's null, it was discarded early, so we
   // have to go back to the object file.
+  // COPY TO: SectionChunk::applyRelARM64.
   ObjFile *file = fromChunk->file;
   std::string name;
   if (sym) {
@@ -457,7 +469,7 @@ void SectionChunk::applyRelocation(uint8_t *off,
     applyRelARM(off, rel.Type, os, s, p, imageBase);
     break;
   case Triple::aarch64:
-    applyRelARM64(off, rel.Type, os, s, p, imageBase);
+    applyRelARM64(off, rel, os, s, p, imageBase);
     break;
   default:
     llvm_unreachable("unknown machine type");
@@ -829,10 +841,17 @@ void ImportThunkChunkARM::writeTo(uint8_t *buf) const {
 }
 
 void ImportThunkChunkARM64::writeTo(uint8_t *buf) const {
-  int64_t off = impSymbol->getRVA() & 0xfff;
   memcpy(buf, importThunkARM64, sizeof(importThunkARM64));
   applyArm64Addr(buf, impSymbol->getRVA(), rva, 12);
-  applyArm64Ldr(buf + 4, off);
+
+  StringRef fileName;
+  if (isa<DefinedImportData>(impSymbol))
+    fileName = static_cast<DefinedImportData *>(impSymbol)->getDLLName();
+  else
+    fileName = "<not_defined_import_data>";
+
+  int64_t off = impSymbol->getRVA() & 0xfff;
+  applyArm64Ldr(impSymbol->getName() + "@" + fileName, buf + 4, off);
 }
 
 // A Thumb2, PIC, non-interworking range extension thunk.
diff --git a/lld/COFF/Chunks.h b/lld/COFF/Chunks.h
index 9f68d5a325cc5..0e04f7b82cc20 100644
--- a/lld/COFF/Chunks.h
+++ b/lld/COFF/Chunks.h
@@ -280,7 +280,7 @@ class SectionChunk : public Chunk {
                    uint64_t p, uint64_t imageBase) const;
   void applyRelARM(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s,
                    uint64_t p, uint64_t imageBase) const;
-  void applyRelARM64(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s,
+  void applyRelARM64(uint8_t *off, const coff_relocation &rel, OutputSection *os, uint64_t s,
                      uint64_t p, uint64_t imageBase) const;
 
   void getRuntimePseudoRelocs(std::vector<RuntimePseudoReloc> &res);

@GulinSS
Copy link
Author

GulinSS commented Apr 9, 2025

Both errors are:


FAILED: tools/lld/COFF/CMakeFiles/lldCOFF.dir/Chunks.cpp.obj
--
  | sccache C:\BuildTools\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64\cl.exe  /nologo /TP -DGTEST_HAS_RTTI=0 -DUNICODE -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS -D_GLIBCXX_ASSERTIONS -D_HAS_EXCEPTIONS=0 -D_SCL_SECURE_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS -D_UNICODE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -Itools\lld\COFF -IC:\ws\src\lld\COFF -IC:\ws\src\lld\include -Itools\lld\include -Iinclude -IC:\ws\src\llvm\include /DWIN32 /D_WINDOWS   /Zc:inline /Zc:preprocessor /Zc:__cplusplus /Oi /bigobj /permissive- /W4 -wd4141 -wd4146 -wd4244 -wd4267 -wd4291 -wd4351 -wd4456 -wd4457 -wd4458 -wd4459 -wd4503 -wd4624 -wd4722 -wd4100 -wd4127 -wd4512 -wd4505 -wd4610 -wd4510 -wd4702 -wd4245 -wd4706 -wd4310 -wd4701 -wd4703 -wd4389 -wd4611 -wd4805 -wd4204 -wd4577 -wd4091 -wd4592 -wd4319 -wd4709 -wd5105 -wd4324 -wd4251 -wd4275 -w14062 -we4238 /Gw /O2 /Ob2  -MD   -wd4530 -wd4062  /EHs-c- /GR- -UNDEBUG -std:c++17 /showIncludes /Fotools\lld\COFF\CMakeFiles\lldCOFF.dir\Chunks.cpp.obj /Fdtools\lld\COFF\CMakeFiles\lldCOFF.dir\lldCOFF.pdb /FS -c C:\ws\src\lld\COFF\Chunks.cpp
  | C:\ws\src\lld\COFF\Chunks.cpp(1154): error C2660: 'lld::coff::applyArm64Ldr': function does not take 2 arguments

Are these due of old caches? Any clues would be helpful!

@GulinSS GulinSS changed the title More logging info for lld [lld] More info for aarch64 ldr/str misaligning error Apr 9, 2025
@mstorsjo
Copy link
Member

mstorsjo commented Apr 9, 2025

Both errors are:

FAILED: tools/lld/COFF/CMakeFiles/lldCOFF.dir/Chunks.cpp.obj
--
  | sccache C:\BuildTools\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64\cl.exe  /nologo /TP -DGTEST_HAS_RTTI=0 -DUNICODE -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS -D_GLIBCXX_ASSERTIONS -D_HAS_EXCEPTIONS=0 -D_SCL_SECURE_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS -D_UNICODE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -Itools\lld\COFF -IC:\ws\src\lld\COFF -IC:\ws\src\lld\include -Itools\lld\include -Iinclude -IC:\ws\src\llvm\include /DWIN32 /D_WINDOWS   /Zc:inline /Zc:preprocessor /Zc:__cplusplus /Oi /bigobj /permissive- /W4 -wd4141 -wd4146 -wd4244 -wd4267 -wd4291 -wd4351 -wd4456 -wd4457 -wd4458 -wd4459 -wd4503 -wd4624 -wd4722 -wd4100 -wd4127 -wd4512 -wd4505 -wd4610 -wd4510 -wd4702 -wd4245 -wd4706 -wd4310 -wd4701 -wd4703 -wd4389 -wd4611 -wd4805 -wd4204 -wd4577 -wd4091 -wd4592 -wd4319 -wd4709 -wd5105 -wd4324 -wd4251 -wd4275 -w14062 -we4238 /Gw /O2 /Ob2  -MD   -wd4530 -wd4062  /EHs-c- /GR- -UNDEBUG -std:c++17 /showIncludes /Fotools\lld\COFF\CMakeFiles\lldCOFF.dir\Chunks.cpp.obj /Fdtools\lld\COFF\CMakeFiles\lldCOFF.dir\lldCOFF.pdb /FS -c C:\ws\src\lld\COFF\Chunks.cpp
  | C:\ws\src\lld\COFF\Chunks.cpp(1154): error C2660: 'lld::coff::applyArm64Ldr': function does not take 2 arguments

Are these due of old caches? Any clues would be helpful!

No, this isn't due to caches - your PR does not compile; did you try compiling it before submitting the PR?

The reason is that in the latest git version of LLD there's a new call to applyArm64Ldr at line 1154 which probably wasn't there, in the version of LLD where you did your modifications initially.

Now as for the change itself. Yes, these errors are frustratingly unactionable in their current form; normally you wouldn't really be hitting them, but when developing a toolchain I guess it is possible to hit them. I have considered improving this diagnostic myself the last time I touched this area.

But most code LLD is very much tuned for linking performance. Digging up info about the symbol name and file name and constructing that into a string (ok Twine), for use if we need to report an error, for every single relocation we do, feels quite unusual compared with how things normally are done in LLD. (LLD even takes the liberty and has the design that it is allowed to crash on erroneous inputs - even if printing a diagnostic obviously is nicer.) Although Twines are quite cheap so it doesn't make much of a measurable practical difference. But I still think we'd want to go slightly differently about it, to only dig up and construct info about the location if we actually do need it. Or what do others, e.g. @rnk and @aganea think here?

Then finally, if we are spending effort on prouducing a good diagnostic here, we should probably also make a testcase for it. (We didn't have a test for the previous error message, as it was mostly seen as something like an assert.)

@GulinSS
Copy link
Author

GulinSS commented Apr 10, 2025

The reason is that in the latest git version of LLD there's a new call to applyArm64Ldr at line 1154 which probably wasn't there, in the version of LLD where you did your modifications initially.

Ah, yes, thanks! I will handle that. Originally this commit had been prepared for LLVM-19 but rebased on actual master later. Sounds like I messed the setup and was unable to clearly check the build.

Thanks again for the pointing.

But I still think we'd want to go slightly differently about it, to only dig up and construct info about the location if we actually do need it.

I am completely agree with that but to make it by my hands some additional guiding is needed. 🙏 Originally this change was only for single purpose: collect more context about this error message.

@mstorsjo
Copy link
Member

But I still think we'd want to go slightly differently about it, to only dig up and construct info about the location if we actually do need it.

I am completely agree with that but to make it by my hands some additional guiding is needed. 🙏 Originally this change was only for single purpose: collect more context about this error message.

Yeah I'm not sure what the best way to solve this is (otherwise I would probably have made a fix long time ago already); let's see if others have good ideas about how to do it. (Also CC @MaskRay for more ideas about how to do this neatly.) This would be neat to do e.g. with an exception, but we don't use exceptions in the LLVM codebase. So perhaps we could return some error code inside the functions handling the relocations, and if the relocation functions indicate an error, we'd gather context about where it is, and print the error.

@MaskRay
Copy link
Member

MaskRay commented Apr 10, 2025

The ELF port relies more heavily on errorOrWarn than on error. When the --noinhibit-exec option is used, errorOrWarn triggers a warning without preventing the output file from being generated. You can typically examine the output file using tools like llvm-readelf or llvm-objdump -dr, or employ the -Map option to create a link map for reviewing input sections. The functions in lld/ELF/Target.h:checkInt produce detailed diagnostics, which could serve as inspiration for the COFF port.

In contrast, the COFF port seems to use errorOrWarn only with the /force:unresolved option. This approach could potentially be expanded for broader application.

In addition, I have noticed that a few similar error in COFF/Chunks.cpp do not have test coverage. In ELF, we could test relocation ranges with absolute symbols (e.g. lld/test/ELF/aarch64-reloc-plt32.s) or linker script (e.g. ppc64-pcrel-call-to-toc-error.s)

@GulinSS
Copy link
Author

GulinSS commented Apr 10, 2025

You can typically examine the output file using tools like llvm-readelf or llvm-objdump -dr, or employ the -Map option to create a link map for reviewing input sections

That is first what I tried. But it has lots of context to find the actual reason. Precise error message works better for such cases. No time wasting.

Copy link
Member

@aganea aganea left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But most code LLD is very much tuned for linking performance. Digging up info about the symbol name and file name and constructing that into a string (ok Twine), for use if we need to report an error, for every single relocation we do, feels quite unusual compared with how things normally are done in LLD. (LLD even takes the liberty and has the design that it is allowed to crash on erroneous inputs - even if printing a diagnostic obviously is nicer.) Although Twines are quite cheap so it doesn't make much of a measurable practical difference. But I still think we'd want to go slightly differently about it, to only dig up and construct info about the location if we actually do need it. Or what do others, e.g. @rnk and @aganea think here?

I think having good diagnostics is important for the user experience. MSVC isn't particularly good at that and neither is LLD, although a bit better than MSVC. Clang and GCC have improved their diagnostics over the past decade. We have the opportunity to improve LLD largerly in that aspect; If we can provide more informative messages, with more context, we should absolutely do it.

In regards to performance, I wonder if we could extend Twine to incorporate llvm::function_ref. I found myself often in such occasions where we're torn between the informative aspect of the message, and not doing too much processing upfront for a error message that might never occur. If we shovel a lambda in the Twine, messages will only be prepared when needed, with no measurable impact if they don't occur.

error("misaligned ldr/str offset");
error(llvm::Twine {"misaligned ldr/str offset: 0x"} + llvm::Twine::utohexstr(imm)
+ "@" + llvm::Twine::utohexstr(static_cast<uint64_t>(orig))
+ " with align 2^" + llvm::Twine(size) + " from " + msg_location);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be better to just display the alignment, ie. llvm::Twine(1 << size)

@mstorsjo
Copy link
Member

I think having good diagnostics is important for the user experience. MSVC isn't particularly good at that and neither is LLD, although a bit better than MSVC.

Definitely. Although this is a quite unusual/internal diagnostic; I'm not really sure how easy it is to even hit this one with just regular user code, unless the toolchain is faulty/broken. But nevertheless, for whoever is working on the potentially faulty toolchain it's not easy to pinpoint the issue unless we give more hints, so I'm all for improving the diagnostics here.

In regards to performance, I wonder if we could extend Twine to incorporate llvm::function_ref. I found myself often in such occasions where we're torn between the informative aspect of the message, and not doing too much processing upfront for a error message that might never occur. If we shovel a lambda in the Twine, messages will only be prepared when needed, with no measurable impact if they don't occur.

That's certainly a good option too. I wonder how much lowlevel overhead there is in such a lambda; probably not much at all? It mostly needs to make sure that any referenced/captured variable is stored in its canonical location in the stack frame of the caller, right?

Another alternative would be to just pass in more of the variables we have in the callers, into the functions, allowing the functions themselves to format everything they want/need once they want to (possibly encapsulated in a helper function). Although I'm not sure if this any better/worse than just passing in a single lambda either. And it forces passing in a lot of parameters we don't usually need.

The tricky part here is actually measuring the performance impact; I did try out this patch (on linking a large-ish binary like clang.exe - that's probably the biggest one I regularly build) and I'm not sure I see any measurable difference with this patch as-is, at least not anything really big. So it's hard to measure and figure out whether it's better to gather everything and just format one single Twine like this does, ahead of time, compared to the cost of setting up and passing in a lambda.

@GulinSS
Copy link
Author

GulinSS commented Apr 11, 2025

probably not much at all? It mostly needs to make sure that any referenced/captured variable is stored in its canonical location in the stack frame of the caller, right?

Add to mind the fact I am a newbie at C++ ) but with more or less detailed guiding I could try.

And it forces passing in a lot of parameters we don't usually need.

It will happen for this case. I tried to make changes locally and it was one reason why I was needed to call procedures which may have impact explicitly on performance.

llvm::function_ref

But adding some sort of laziness would be good here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants