Skip to content

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

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

Closed
ConchuOD opened this issue Sep 24, 2022 · 18 comments
Closed

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

ConchuOD opened this issue Sep 24, 2022 · 18 comments
Assignees
Labels
[ARCH] risc-v This bug impacts ARCH=riscv [FIXED][LINUX] 6.1 This bug was fixed in Linux 6.1 GNU Binutils Interop non-LLVM=1 usage Reported upstream This bug was filed on LLVM’s issue tracker, Phabricator, or the kernel mailing list.

Comments

@ConchuOD
Copy link
Member

ConchuOD commented Sep 24, 2022

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

@nathanchance nathanchance added [ARCH] risc-v This bug impacts ARCH=riscv GNU Binutils Interop non-LLVM=1 usage labels Sep 24, 2022
@ConchuOD
Copy link
Member Author

ConchuOD commented Sep 24, 2022

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

@nickdesaulniers
Copy link
Member

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.

@ConchuOD
Copy link
Member Author

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.

@nathanchance
Copy link
Member

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?

@ConchuOD
Copy link
Member Author

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?

@nickdesaulniers
Copy link
Member

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

@nickdesaulniers nickdesaulniers added the Reported upstream This bug was filed on LLVM’s issue tracker, Phabricator, or the kernel mailing list. label Sep 26, 2022
@nickdesaulniers
Copy link
Member

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.

@nathanchance
Copy link
Member

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

@ConchuOD
Copy link
Member Author

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

@nickdesaulniers
Copy link
Member

Something like the following, perhaps?

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

@nathanchance
Copy link
Member

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.

@ConchuOD
Copy link
Member Author

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 ?

@nathanchance
Copy link
Member

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

@ConchuOD
Copy link
Member Author

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 [email protected]

@nathanchance
Copy link
Member

Patch submitted: https://lore.kernel.org/[email protected]/

@nathanchance nathanchance added the [PATCH] Submitted A patch has been submitted for review label Sep 28, 2022
@nathanchance nathanchance self-assigned this Sep 28, 2022
intel-lab-lkp pushed a commit to intel-lab-lkp/linux that referenced this issue Oct 1, 2022
… DWARF5

When building with a RISC-V kernel with DWARF5 debug info using clang and
the GNU assembler, several instances of the following error appear:

  /tmp/vgettimeofday-48aa35.s:2963: Error: non-constant .uleb128 is not supported

Dumping the .s file reveals these .uleb128 directives come from
.debug_loc and .debug_ranges:

  .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_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

There is an outstanding binutils issue to support a non-constant operand
to .sleb128 and .uleb128 in GAS for RISC-V but there does not appear to be
any movement on it, due to concerns over how it would work with linker
relaxation.

To avoid these build errors, prevent DWARF5 from being selected when using
clang and an assembler that does not have support for these symbol deltas,
which can be easily checked in Kconfig with as-instr plus the small test
program from the dwz test suite from the binutils issue.

Link: https://sourceware.org/bugzilla/show_bug.cgi?id=27215
Link: ClangBuiltLinux#1719
Link: https://lkml.kernel.org/r/[email protected]
Signed-off-by: Nathan Chancellor <[email protected]>
Tested-by: Conor Dooley <[email protected]>
Reviewed-by: Nick Desaulniers <[email protected]>
Cc: Masahiro Yamada <[email protected]>
Cc: Palmer Dabbelt <[email protected]>
Cc: Tom Rix <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
intel-lab-lkp pushed a commit to intel-lab-lkp/linux that referenced this issue Oct 2, 2022
… DWARF5

When building with a RISC-V kernel with DWARF5 debug info using clang and
the GNU assembler, several instances of the following error appear:

  /tmp/vgettimeofday-48aa35.s:2963: Error: non-constant .uleb128 is not supported

Dumping the .s file reveals these .uleb128 directives come from
.debug_loc and .debug_ranges:

  .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_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

There is an outstanding binutils issue to support a non-constant operand
to .sleb128 and .uleb128 in GAS for RISC-V but there does not appear to be
any movement on it, due to concerns over how it would work with linker
relaxation.

To avoid these build errors, prevent DWARF5 from being selected when using
clang and an assembler that does not have support for these symbol deltas,
which can be easily checked in Kconfig with as-instr plus the small test
program from the dwz test suite from the binutils issue.

Link: https://sourceware.org/bugzilla/show_bug.cgi?id=27215
Link: ClangBuiltLinux#1719
Link: https://lkml.kernel.org/r/[email protected]
Signed-off-by: Nathan Chancellor <[email protected]>
Tested-by: Conor Dooley <[email protected]>
Reviewed-by: Nick Desaulniers <[email protected]>
Cc: Masahiro Yamada <[email protected]>
Cc: Palmer Dabbelt <[email protected]>
Cc: Tom Rix <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
@nathanchance
Copy link
Member

torvalds pushed a commit to torvalds/linux that referenced this issue Oct 16, 2022
… DWARF5

When building with a RISC-V kernel with DWARF5 debug info using clang
and the GNU assembler, several instances of the following error appear:

  /tmp/vgettimeofday-48aa35.s:2963: Error: non-constant .uleb128 is not supported

Dumping the .s file reveals these .uleb128 directives come from
.debug_loc and .debug_ranges:

  .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_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

There is an outstanding binutils issue to support a non-constant operand
to .sleb128 and .uleb128 in GAS for RISC-V but there does not appear to
be any movement on it, due to concerns over how it would work with
linker relaxation.

To avoid these build errors, prevent DWARF5 from being selected when
using clang and an assembler that does not have support for these symbol
deltas, which can be easily checked in Kconfig with as-instr plus the
small test program from the dwz test suite from the binutils issue.

Link: https://sourceware.org/bugzilla/show_bug.cgi?id=27215
Link: ClangBuiltLinux#1719
Signed-off-by: Nathan Chancellor <[email protected]>
Reviewed-by: Nick Desaulniers <[email protected]>
Signed-off-by: Masahiro Yamada <[email protected]>
@nathanchance
Copy link
Member

@nathanchance nathanchance removed the [PATCH] Submitted A patch has been submitted for review label Oct 16, 2022
MaskRay added a commit to MaskRay/llvm-project that referenced this issue Aug 27, 2023
…directives

For a label difference like `.uleb128 A-B`, MC folds A-B even if A and B
are separated by a RISC-V linker-relaxable instruction. This incorrect
behavior is currently abused by DWARF v5 .debug_loclists/.debug_rnglists
(DW_LLE_offset_pair/DW_RLE_offset_pair entry kinds) implemented in
Clang/LLVM (see ClangBuiltLinux/linux#1719 for
an instance).

riscv-non-isa/riscv-elf-psabi-doc@96d6e19
defined R_RISCV_SET_ULEB128/R_RISCV_SUB_ULEB128. This patch generates such
a pair of relocations to represent A-B that should not be folded.
GNU assembler computes the directive size by ignoring shrinkable section
content, therefore after linking the value of A-B cannot use more bytes
than the reserved number (`final size of uleb128 value at offset ... exceeds available space`).
We make the same assumption.
```
w1:
  call foo
w2:
  .space 120
w3:
.uleb128 w2-w1  # 1 byte, 0x08
.uleb128 w3-w1  # 2 bytes, 0x80 0x01
```

We do not conservatively reserve 10 bytes (maximum size of an uleb128
for uint64_t) as that would pessimize DWARF v5
DW_LLE_offset_pair/DW_RLE_offset_pair, nullifying the benefits of
introducing R_RISCV_SET_ULEB128/R_RISCV_SUB_ULEB128 relocations.

The supported expressions are limited. For example,

* non-subtraction `.uleb128 A` is not allowed
* `.uleb128 A-B`: report an error unless A and B are both defined and in the same section

The new cl::opt `-riscv-uleb128-reloc` can be used to suppress the
relocations.

Differential Revision: https://reviews.llvm.org/D157657
MaskRay added a commit to llvm/llvm-project that referenced this issue Nov 9, 2023
…directives

For a label difference like `.uleb128 A-B`, MC folds A-B even if A and B
are separated by a RISC-V linker-relaxable instruction. This incorrect
behavior is currently abused by DWARF v5 .debug_loclists/.debug_rnglists
(DW_LLE_offset_pair/DW_RLE_offset_pair entry kinds) implemented in
Clang/LLVM (see ClangBuiltLinux/linux#1719 for
an instance).

riscv-non-isa/riscv-elf-psabi-doc@96d6e19
defined R_RISCV_SET_ULEB128/R_RISCV_SUB_ULEB128. This patch generates such
a pair of relocations to represent A-B that should not be folded.
GNU assembler computes the directive size by ignoring shrinkable section
content, therefore after linking the value of A-B cannot use more bytes
than the reserved number (`final size of uleb128 value at offset ... exceeds available space`).
We make the same assumption.
```
w1:
  call foo
w2:
  .space 120
w3:
.uleb128 w2-w1  # 1 byte, 0x08
.uleb128 w3-w1  # 2 bytes, 0x80 0x01
```

We do not conservatively reserve 10 bytes (maximum size of an uleb128
for uint64_t) as that would pessimize DWARF v5
DW_LLE_offset_pair/DW_RLE_offset_pair, nullifying the benefits of
introducing R_RISCV_SET_ULEB128/R_RISCV_SUB_ULEB128 relocations.

The supported expressions are limited. For example,

* non-subtraction `.uleb128 A` is not allowed
* `.uleb128 A-B`: report an error unless A and B are both defined and in the same section

The new cl::opt `-riscv-uleb128-reloc` can be used to suppress the
relocations.

Reviewed By: asb

Differential Revision: https://reviews.llvm.org/D157657
zahiraam pushed a commit to zahiraam/llvm-project that referenced this issue Nov 20, 2023
…directives

For a label difference like `.uleb128 A-B`, MC folds A-B even if A and B
are separated by a RISC-V linker-relaxable instruction. This incorrect
behavior is currently abused by DWARF v5 .debug_loclists/.debug_rnglists
(DW_LLE_offset_pair/DW_RLE_offset_pair entry kinds) implemented in
Clang/LLVM (see ClangBuiltLinux/linux#1719 for
an instance).

riscv-non-isa/riscv-elf-psabi-doc@96d6e19
defined R_RISCV_SET_ULEB128/R_RISCV_SUB_ULEB128. This patch generates such
a pair of relocations to represent A-B that should not be folded.
GNU assembler computes the directive size by ignoring shrinkable section
content, therefore after linking the value of A-B cannot use more bytes
than the reserved number (`final size of uleb128 value at offset ... exceeds available space`).
We make the same assumption.
```
w1:
  call foo
w2:
  .space 120
w3:
.uleb128 w2-w1  # 1 byte, 0x08
.uleb128 w3-w1  # 2 bytes, 0x80 0x01
```

We do not conservatively reserve 10 bytes (maximum size of an uleb128
for uint64_t) as that would pessimize DWARF v5
DW_LLE_offset_pair/DW_RLE_offset_pair, nullifying the benefits of
introducing R_RISCV_SET_ULEB128/R_RISCV_SUB_ULEB128 relocations.

The supported expressions are limited. For example,

* non-subtraction `.uleb128 A` is not allowed
* `.uleb128 A-B`: report an error unless A and B are both defined and in the same section

The new cl::opt `-riscv-uleb128-reloc` can be used to suppress the
relocations.

Reviewed By: asb

Differential Revision: https://reviews.llvm.org/D157657
jiegec pushed a commit to AOSC-Tracking/llvm-project that referenced this issue Feb 13, 2024
…directives

For a label difference like `.uleb128 A-B`, MC folds A-B even if A and B
are separated by a RISC-V linker-relaxable instruction. This incorrect
behavior is currently abused by DWARF v5 .debug_loclists/.debug_rnglists
(DW_LLE_offset_pair/DW_RLE_offset_pair entry kinds) implemented in
Clang/LLVM (see ClangBuiltLinux/linux#1719 for
an instance).

riscv-non-isa/riscv-elf-psabi-doc@96d6e19
defined R_RISCV_SET_ULEB128/R_RISCV_SUB_ULEB128. This patch generates such
a pair of relocations to represent A-B that should not be folded.
GNU assembler computes the directive size by ignoring shrinkable section
content, therefore after linking the value of A-B cannot use more bytes
than the reserved number (`final size of uleb128 value at offset ... exceeds available space`).
We make the same assumption.
```
w1:
  call foo
w2:
  .space 120
w3:
.uleb128 w2-w1  # 1 byte, 0x08
.uleb128 w3-w1  # 2 bytes, 0x80 0x01
```

We do not conservatively reserve 10 bytes (maximum size of an uleb128
for uint64_t) as that would pessimize DWARF v5
DW_LLE_offset_pair/DW_RLE_offset_pair, nullifying the benefits of
introducing R_RISCV_SET_ULEB128/R_RISCV_SUB_ULEB128 relocations.

The supported expressions are limited. For example,

* non-subtraction `.uleb128 A` is not allowed
* `.uleb128 A-B`: report an error unless A and B are both defined and in the same section

The new cl::opt `-riscv-uleb128-reloc` can be used to suppress the
relocations.

Reviewed By: asb

Differential Revision: https://reviews.llvm.org/D157657
hack3ric pushed a commit to hack3ric/llvm-project-rocm that referenced this issue Feb 20, 2024
…directives

For a label difference like `.uleb128 A-B`, MC folds A-B even if A and B
are separated by a RISC-V linker-relaxable instruction. This incorrect
behavior is currently abused by DWARF v5 .debug_loclists/.debug_rnglists
(DW_LLE_offset_pair/DW_RLE_offset_pair entry kinds) implemented in
Clang/LLVM (see ClangBuiltLinux/linux#1719 for
an instance).

riscv-non-isa/riscv-elf-psabi-doc@96d6e19
defined R_RISCV_SET_ULEB128/R_RISCV_SUB_ULEB128. This patch generates such
a pair of relocations to represent A-B that should not be folded.
GNU assembler computes the directive size by ignoring shrinkable section
content, therefore after linking the value of A-B cannot use more bytes
than the reserved number (`final size of uleb128 value at offset ... exceeds available space`).
We make the same assumption.
```
w1:
  call foo
w2:
  .space 120
w3:
.uleb128 w2-w1  # 1 byte, 0x08
.uleb128 w3-w1  # 2 bytes, 0x80 0x01
```

We do not conservatively reserve 10 bytes (maximum size of an uleb128
for uint64_t) as that would pessimize DWARF v5
DW_LLE_offset_pair/DW_RLE_offset_pair, nullifying the benefits of
introducing R_RISCV_SET_ULEB128/R_RISCV_SUB_ULEB128 relocations.

The supported expressions are limited. For example,

* non-subtraction `.uleb128 A` is not allowed
* `.uleb128 A-B`: report an error unless A and B are both defined and in the same section

The new cl::opt `-riscv-uleb128-reloc` can be used to suppress the
relocations.

Reviewed By: asb

Differential Revision: https://reviews.llvm.org/D157657
MingcongBai pushed a commit to AOSC-Tracking/llvm-project that referenced this issue Mar 26, 2024
…directives

For a label difference like `.uleb128 A-B`, MC folds A-B even if A and B
are separated by a RISC-V linker-relaxable instruction. This incorrect
behavior is currently abused by DWARF v5 .debug_loclists/.debug_rnglists
(DW_LLE_offset_pair/DW_RLE_offset_pair entry kinds) implemented in
Clang/LLVM (see ClangBuiltLinux/linux#1719 for
an instance).

riscv-non-isa/riscv-elf-psabi-doc@96d6e19
defined R_RISCV_SET_ULEB128/R_RISCV_SUB_ULEB128. This patch generates such
a pair of relocations to represent A-B that should not be folded.
GNU assembler computes the directive size by ignoring shrinkable section
content, therefore after linking the value of A-B cannot use more bytes
than the reserved number (`final size of uleb128 value at offset ... exceeds available space`).
We make the same assumption.
```
w1:
  call foo
w2:
  .space 120
w3:
.uleb128 w2-w1  # 1 byte, 0x08
.uleb128 w3-w1  # 2 bytes, 0x80 0x01
```

We do not conservatively reserve 10 bytes (maximum size of an uleb128
for uint64_t) as that would pessimize DWARF v5
DW_LLE_offset_pair/DW_RLE_offset_pair, nullifying the benefits of
introducing R_RISCV_SET_ULEB128/R_RISCV_SUB_ULEB128 relocations.

The supported expressions are limited. For example,

* non-subtraction `.uleb128 A` is not allowed
* `.uleb128 A-B`: report an error unless A and B are both defined and in the same section

The new cl::opt `-riscv-uleb128-reloc` can be used to suppress the
relocations.

Reviewed By: asb

Differential Revision: https://reviews.llvm.org/D157657
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[ARCH] risc-v This bug impacts ARCH=riscv [FIXED][LINUX] 6.1 This bug was fixed in Linux 6.1 GNU Binutils Interop non-LLVM=1 usage Reported upstream This bug was filed on LLVM’s issue tracker, Phabricator, or the kernel mailing list.
Projects
None yet
Development

No branches or pull requests

3 participants