ClangBuiltLinux/linux

LLVM/GNU binutils interop: non-constant .uleb128 is not supported

ConchuOD opened this issue · 18 comments

Nathan poked me about this on IRC the other day, but I'll probably forget about it so making an issue.

/tmp/vgettimeofday-189a65.s: Assembler messages:
/tmp/vgettimeofday-189a65.s:2535: Error: non-constant .uleb128 is not supported

build log
build env

Looks like this may be a gas issue that has been fixed, but idk what the gnu toolchain lads do by way of backporting.
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91602#c16

Seems like the fix was for GCC to do configure time checking of GAS' capabilities. We don't have such luxury when building clang itself; we probably need some kind of as-option check for this and see if we can get clang to disable emitting these directives when LLVM_IAS=0.

Seems like the fix was for GCC to do configure time checking of GAS' capabilities. We don't have such luxury when building clang itself; we probably need some kind of as-option check for this and see if we can get clang to disable emitting these directives when LLVM_IAS=0.

I'll take your word for it! I mentioned backporting as I could not repro with newer versions of binutils.

This is reproducible with binutils master, which appears not to have support for non-constant .uleb128 or .sleb128.

$ sed -n '4427,4440p' gas/config/tc-riscv.c
static void
s_riscv_leb128 (int sign)
{
  expressionS exp;
  char *save_in = input_line_pointer;

  expression (&exp);
  if (exp.X_op != O_constant)
    as_bad (_("non-constant .%cleb128 is not supported"), sign ? 's' : 'u');
  demand_empty_rest_of_line ();

  input_line_pointer = save_in;
  return s_leb128 (sign);
}

It looks like the .uleb128 comes from debug info? If I manually generate arch/riscv/kernel/vdso/vgettimeofday.s from arch/riscv/kernel/vdso/vgettimeofday.c using -fverbose-asm -S, I see:

...
.Ldebug_loc0:
        .byte   4                               # DW_LLE_offset_pair
        .uleb128 .Lfunc_begin0-.Lfunc_begin0    #   starting offset
        .uleb128 .Ltmp1-.Lfunc_begin0           #   ending offset
        .byte   1                               # Loc expr size
        .byte   90                              # DW_OP_reg10
        .byte   0                               # DW_LLE_end_of_list
.Ldebug_loc1:
        .byte   4                               # DW_LLE_offset_pair
        .uleb128 .Lfunc_begin0-.Lfunc_begin0    #   starting offset
        .uleb128 .Ltmp1-.Lfunc_begin0           #   ending offset
        .byte   1                               # Loc expr size
        .byte   91                              # DW_OP_reg11
        .byte   0                               # DW_LLE_end_of_list
.Ldebug_loc2:
        .byte   4                               # DW_LLE_offset_pair
        .uleb128 .Lfunc_begin1-.Lfunc_begin0    #   starting offset
        .uleb128 .Ltmp4-.Lfunc_begin0           #   ending offset
        .byte   1                               # Loc expr size
        .byte   90                              # DW_OP_reg10
        .byte   0                               # DW_LLE_end_of_list
.Ldebug_loc3:
        .byte   4                               # DW_LLE_offset_pair
        .uleb128 .Lfunc_begin1-.Lfunc_begin0    #   starting offset
        .uleb128 .Ltmp4-.Lfunc_begin0           #   ending offset
        .byte   1                               # Loc expr size
        .byte   91                              # DW_OP_reg11
        .byte   0                               # DW_LLE_end_of_list
...
.Ldebug_ranges0:
        .byte   4                               # DW_RLE_offset_pair
        .uleb128 .Ltmp6-.Lfunc_begin0           #   starting offset
        .uleb128 .Ltmp27-.Lfunc_begin0          #   ending offset
        .byte   4                               # DW_RLE_offset_pair
        .uleb128 .Ltmp28-.Lfunc_begin0          #   starting offset
        .uleb128 .Ltmp30-.Lfunc_begin0          #   ending offset
        .byte   0                               # DW_RLE_end_of_list
.Ldebug_ranges1:
        .byte   4                               # DW_RLE_offset_pair
        .uleb128 .Ltmp6-.Lfunc_begin0           #   starting offset
        .uleb128 .Ltmp27-.Lfunc_begin0          #   ending offset
        .byte   4                               # DW_RLE_offset_pair
        .uleb128 .Ltmp28-.Lfunc_begin0          #   starting offset
        .uleb128 .Ltmp30-.Lfunc_begin0          #   ending offset
        .byte   0                               # DW_RLE_end_of_list
.Ldebug_ranges2:
        .byte   4                               # DW_RLE_offset_pair
        .uleb128 .Ltmp6-.Lfunc_begin0           #   starting offset
        .uleb128 .Ltmp16-.Lfunc_begin0          #   ending offset
        .byte   4                               # DW_RLE_offset_pair
        .uleb128 .Ltmp17-.Lfunc_begin0          #   starting offset
        .uleb128 .Ltmp22-.Lfunc_begin0          #   ending offset
        .byte   4                               # DW_RLE_offset_pair
        .uleb128 .Ltmp25-.Lfunc_begin0          #   starting offset
        .uleb128 .Ltmp27-.Lfunc_begin0          #   ending offset
        .byte   0                               # DW_RLE_end_of_list
...

Which seems to correspond to

https://github.com/llvm/llvm-project/blob/c418f00536001169f40d09bf3bff568aacfc9c30/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp#L303-L307
https://github.com/llvm/llvm-project/blob/bc13437b156abc41f835a6a3ef5efb571b815872/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp#L2797-L2803

I guess we could just restrict CONFIG_DEBUG_INFO_DWARF5 to require the integrated assembler when building with clang to workaround this?

I was sure tried 2.37 & 2.38 before 2.35.2 and could not repro it there.. Consider me very confused now as to what I actually tested!

I guess we could just restrict CONFIG_DEBUG_INFO_DWARF5 to require the integrated assembler when building with clang to workaround this?

Do you even have another option?

Looks like there's an open bug report for this against GNU binutils.
https://sourceware.org/bugzilla/show_bug.cgi?id=27215

I guess we could just restrict CONFIG_DEBUG_INFO_DWARF5 to require the integrated assembler when building with clang to workaround this?

and just for riscv. Or use as-instr.

Or use as-instr.

Ah, great idea, especially with Martin's reproducer from the binutils issue. Something like the following, perhaps?

diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index d3e5f36bb01e..77bc73d0d8dc 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -231,6 +231,9 @@ config DEBUG_INFO
          in the "Debug information" choice below, indicating that debug
          information will be generated for build targets.

+config AS_HAS_NON_CONST_LEB128
+       def_bool $(as-instr,.uleb128 .Lexpr_end4 - .Lexpr_start3\n.Lexpr_start3:\n.Lexpr_end4:)
+
 choice
        prompt "Debug information"
        depends on DEBUG_KERNEL
@@ -276,7 +279,7 @@ config DEBUG_INFO_DWARF4
 config DEBUG_INFO_DWARF5
        bool "Generate DWARF Version 5 debuginfo"
        select DEBUG_INFO
-       depends on !CC_IS_CLANG || (CC_IS_CLANG && (AS_IS_LLVM || (AS_IS_GNU && AS_VERSION >= 23502)))
+       depends on !CC_IS_CLANG || (CC_IS_CLANG && (AS_IS_LLVM || (AS_IS_GNU && AS_VERSION >= 23502)) && AS_HAS_NON_CONST_LEB128)
        help
          Generate DWARF v5 debug info. Requires binutils 2.35.2, gcc 5.0+ (gcc
          5.0+ accepts the -gdwarf-5 flag but only had partial support for some

The above works, but maybe the line length could do with some improvement!

Something like the following, perhaps?

Maybe add another depends on line, and make it riscv specific?

Maybe add another depends on line, and make it riscv specific?

I can move it to a different depends on line (although that unnecessarily applies this restriction to GCC, which clearly does not have this issue) but I don't really see the point in special casing RISC-V here. CONFIG_AS_HAS_NON_CONST_LEB128 should be true for every other architecture so there is not much point in limiting its scope.

Maybe add another depends on line, and make it riscv specific?

I can move it to a different depends on line (although that unnecessarily applies this restriction to GCC, which clearly does not have this issue) but I don't really see the point in special casing RISC-V here. CONFIG_AS_HAS_NON_CONST_LEB128 should be true for every other architecture so there is not much point in limiting its scope.

Is there something that prevents you from also starting the second depends on line with a !GCC ?

No, I am sure this would work just fine:

diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index d3e5f36bb01e..19de03ead2ed 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -231,6 +231,9 @@ config DEBUG_INFO
          in the "Debug information" choice below, indicating that debug
          information will be generated for build targets.

+config AS_HAS_NON_CONST_LEB128
+       def_bool $(as-instr,.uleb128 .Lexpr_end4 - .Lexpr_start3\n.Lexpr_start3:\n.Lexpr_end4:)
+
 choice
        prompt "Debug information"
        depends on DEBUG_KERNEL
@@ -277,6 +280,10 @@ config DEBUG_INFO_DWARF5
        bool "Generate DWARF Version 5 debuginfo"
        select DEBUG_INFO
        depends on !CC_IS_CLANG || (CC_IS_CLANG && (AS_IS_LLVM || (AS_IS_GNU && AS_VERSION >= 23502)))
+       # Clang is known to generate .{s,u}leb128 with symbol deltas with
+       # DWARF5, which some targets may not support.
+       # https://sourceware.org/bugzilla/show_bug.cgi?id=27215
+       depends on !CC_IS_CLANG || AS_HAS_NON_CONST_LEB128
        help
          Generate DWARF v5 debug info. Requires binutils 2.35.2, gcc 5.0+ (gcc
          5.0+ accepts the -gdwarf-5 flag but only had partial support for some

No, I am sure this would work just fine:

diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index d3e5f36bb01e..19de03ead2ed 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -231,6 +231,9 @@ config DEBUG_INFO
          in the "Debug information" choice below, indicating that debug
          information will be generated for build targets.

+config AS_HAS_NON_CONST_LEB128
+       def_bool $(as-instr,.uleb128 .Lexpr_end4 - .Lexpr_start3\n.Lexpr_start3:\n.Lexpr_end4:)
+
 choice
        prompt "Debug information"
        depends on DEBUG_KERNEL
@@ -277,6 +280,10 @@ config DEBUG_INFO_DWARF5
        bool "Generate DWARF Version 5 debuginfo"
        select DEBUG_INFO
        depends on !CC_IS_CLANG || (CC_IS_CLANG && (AS_IS_LLVM || (AS_IS_GNU && AS_VERSION >= 23502)))
+       # Clang is known to generate .{s,u}leb128 with symbol deltas with
+       # DWARF5, which some targets may not support.
+       # https://sourceware.org/bugzilla/show_bug.cgi?id=27215
+       depends on !CC_IS_CLANG || AS_HAS_NON_CONST_LEB128
        help
          Generate DWARF v5 debug info. Requires binutils 2.35.2, gcc 5.0+ (gcc
          5.0+ accepts the -gdwarf-5 flag but only had partial support for some

This looks good to me! Feel free to submit with a:
Tested-by: Conor Dooley conor.dooley@microchip.com

I have requested a backport to 5.15, 5.19, and 6.0: https://lore.kernel.org/Y02WW7iIeWPFTV8L@dev-arch.thelio-3990X/