[ELF] Support . and $ in symbol names in expressions

GNU ld supports `.` and `$` in symbol names while LLD doesn't support them in
`readPrimary` expressions. Using `.` can result in such an error:

```
https://github.com/ClangBuiltLinux/linux/issues/1318
ld.lld: error: ./arch/powerpc/kernel/vmlinux.lds:255: malformed number: .TOC.
>>>   __toc_ptr = (DEFINED (.TOC.) ? .TOC. : ADDR (.got)) + 0x8000;
```

Allow `.` (ppc64 special symbol `.TOC.`) and `$` (RISC-V special symbol `__global_pointer$`).

Change `diag[3-5].test` to use an invalid character `^`.

Note: GNU ld allows `~` in non-leading positions of a symbol name.  `~`
is not used in practice, conflicts with the unary operator, and can
cause some parsing difficulty, so this patch does not add it.

Differential Revision: https://reviews.llvm.org/D98306
This commit is contained in:
Fangrui Song
2021-03-11 09:34:36 -08:00
parent 9c841cb8e8
commit e4f385d894
5 changed files with 26 additions and 11 deletions

View File

@@ -1234,6 +1234,13 @@ static void checkIfExists(OutputSection *cmd, StringRef location) {
error(location + ": undefined section " + cmd->name);
}
static bool isValidSymbolName(StringRef s) {
auto valid = [](char c) {
return isAlnum(c) || c == '$' || c == '.' || c == '_';
};
return !s.empty() && !isDigit(s[0]) && llvm::all_of(s, valid);
}
Expr ScriptParser::readPrimary() {
if (peek() == "(")
return readParenExpr();
@@ -1408,7 +1415,7 @@ Expr ScriptParser::readPrimary() {
return [=] { return *val; };
// Tok is a symbol name.
if (!isValidCIdentifier(tok))
if (!isValidSymbolName(tok))
setError("malformed number: " + tok);
script->referencedSymbols.push_back(tok);
return [=] { return script->getSymbolValue(tok, location); };