【问题标题】:llvm naming policy for llvm-IR variables and assembler symbolsllvm-IR 变量和汇编符号的 llvm 命名策略
【发布时间】:2020-10-01 11:15:30
【问题描述】:

正如我所见,llvm 支持以 null 结尾的字符串,包括任何字符(0x01 到 0xff)作为 llvm-IR 变量和汇编符号的有效名称。在我看来,这样的决定可能会导致一些问题。

  1. 当名称包含“特殊”(不可打印)字符时,很难使用文本编辑器(Vim、Kate 等)在 llvm-IR 和汇编程序中编辑程序
  2. LLvm 和汇编程序支持使用双引号转义,例如"A B" 是一个带有空格字符的名称。在特殊字符的编码中期望类似 printf 的风格是合乎逻辑的。我的意思是"\n""\t""\xAB",但 llvm-IR 和汇编程序不支持这种名称样式(但 llvm 支持 \KL 用于初始化程序)。
  • 一方面"A\n" 产生的不是"A"newline character,而是对象elf 文件中包含所有3 个字节的名称
  • 另一方面,"A\n""A\\n" 为 llvm 生成相同的名称

(所以看起来即使是 llvm 也不支持以任何适当的方式进行特殊命名。)

@"A\n"   = internal constant i32 1
@"A\\n"  = internal constant i32 2
$ clang-9 test.ll -S
test.ll:3:1: error: redefinition of global '@A\n'
@"A\\n"  = internal constant i32 2
  1. @GOTOFF@plt 是怎么回事?如何区分包括 @GOTOFF 在内的名称与汇编程序重定位规范?为什么"A B@GOTOFF"可以组装,而"A B"@GOTOFF不行?

  2. Bug https://sourceware.org/bugzilla/show_bug.cgi?id=18581 于 2015 年开放,但即使是现在,gas 也不支持名称中的某些字符,而 llvm 支持。例如 "A,B""A\B" 不能用气体组装。 所以llvm创建了汇编方言,不能通过gas进行组装。

编程语言(C/C++、Rust、Go、Python、Java 等)仅支持标识符中的 lettersdigits'_''$' 字符。前端也使用 '.''$''#' 字符,但无论如何它们会生成在汇编程序中有效的名称(没有任何双引号转义)。

可能只有 llvm 优化会生成带有特殊字符的名称。但是这些名称仅为具有内部(C 术语中的静态)链接的全局变量创建。那么为什么不对这些全局变量使用像 "__llvm_internal_global_Id_*" 这样的特殊模式(某些名称在所有情况下都是保留的)?

那么使用这种命名策略的原因是什么?使用一组小而简单的有效字符进行命名会更好吗?

【问题讨论】:

  • 这里有一些不好的假设。您对java identifiers 的描述完全错误,到目前为止,我还没有看到任何创建非ascii 标识符的通行证(您称之为优化)。如果煤气不起作用,为什么还要费心呢?现在所有酷孩子都编译为目标代码。
  • 嗯。我的措辞可能是错误的。我不知道,但我现在已经在一个 bug 上花费了六个小时,这往往会影响我的行为方式,所以...抱歉。
  • 我在大约 3 周的时间里只调试了一个错误(它是来自 Firefox 的 SpiderMonkey JIT 中 mips 解释器的更快版本)。这很“有趣”,所以没问题。现在我不知道哪个 pass(es) 创建了“内部常量全局变量”,但似乎字符串常量的优化创建了一个名称等于值的全局变量。因此,字符串中的所有字符都成为名称的字符。就是这样(我认为是这样)。我在 clang、rust、python3/numba/llvmlite 中看到了这样的情况。
  • 基于我阅读的 2003-2004 年提交,这是故意的。这是有道理的,因为 LLVM 的目标之一是简化前端的编写。所以它的标识符允许大字符集并且没有长度限制。还有其他类似的决定:对行长没有限制,对结构中的字段数没有限制。生成的代码经常会产生丑陋的结果,我见过丑陋的名字、丑陋的类型和丑陋的线条。
  • 使用少量但简单的有效字符集进行命名会更好吗? - 我希望大多数前端都会这样做,尤其是当 asm 符号名称时来自高级语言标识符。在我看来,LLVM 不会浪费代码对名称进行一些限制,这似乎很正常。对于某些可能的(未来?)前端来说,这会更慢并且可能不方便。相反,实际可用的限制来自 LLVM-IR 文本解析器,以及常识/人类可用性。 (至少这是我对如何明智地看待这种情况的猜测)。

标签: assembly llvm llvm-ir gnu-assembler


【解决方案1】:

我将尝试总结中期结果。

llvm 支持 llvm-IR 变量名和 asm 符号名作为任意字符的序列。总的来说,它看起来是一个很好的解决方案。

但目前的认识有一些特殊的时刻。

  1. llvm-parser 可以与 llvm-IR 一起使用,其中字符串初始化器和全局变量的名称都包含转义序列(使用“\AB”-pattern,其中 0xAB 是十六进制代码)。但在汇编语言中,转义序列不使用或/并且不起作用(还有 readelf、objdump、gdb 等)。这一事实给文本编辑器的使用带来了问题。

  2. 汇编语言在符号名称之后使用特殊的重定位修饰符,例如 @plt@GOTOFF 和其他。因此,当符号名称(双引号中)包含像"@plt" 这样的子字符串时,这是一个冲突。并且我为汇编器词法解析器提出了一个简单的规则

A@plt       - symbol with name 'A' and plt-relocation
"A@plt"     - symbol with name 'A@plt'
"A@plt"@plt - symbol with name 'A@plt' and plt-relocation

(所以双引号中的都是名称的一部分,双引号之后或符号名称末尾的都是重定位修饰符)。

  1. Gas 声明支持(https://sourceware.org/binutils/docs/as/Symbol-Intro.html#Symbol-Intro),但实际上不支持符号名称中的",""\"。所以gas中的有效符号名称集比llvm-as中的要少。

而且我希望这些时刻能够在 llvm 和 gas 中得到修复(如果这是对当前情况的正确描述的话)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-03
    • 2021-07-18
    • 1970-01-01
    • 2015-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多