Repository: SUSE/libpulp
Pull request #241: ppc64le: rewrite ASM code to not generate TEXTREL
Author: login: giulianobelinassi
Created: 2025-04-02T16:00:55Z | Merged: 2025-04-04T13:58:07Z

Previous versions of libpulp for the ppc64le generated text relocations, which makes the dynamic linker resolve them when the library is being loaded.  This actually causes a problem when the program is loaded with seccomp mprotect protection, because it needs to set the page to EXECUTABLE and WRITABLE for a short period of time, causing the application to crash.

This commit fixes this by refatoring the code into not using TEXTREL. This comes with a performance cost because __tls_get_addr needs to be called in order for this to work, and more registers needs to be saved for this function to be successfully called.


Diff:
diff --git a/lib/arch/powerpc64le/patch.c b/lib/arch/powerpc64le/patch.c
index 99bab5d7..ccb0eade 100644
--- a/lib/arch/powerpc64le/patch.c
+++ b/lib/arch/powerpc64le/patch.c
@@ -249,8 +249,10 @@ ulp_pthread_key_init(void)
  * In the ulp prologue in ppc64le we need to save the TOC and LR registers
  * before redirect into a new function, and we store it in a stack allocated
  * by mmap.  This routine does exactly this.
+ *
+ * @return  The address of the ulp_stack object.
  */
-void ulp_stack_helper(void)
+void *ulp_stack_helper(void)
 {
   /* Comparison should have been done in trampoline_routine (this function
      caller), so just assert it here.  */
@@ -276,7 +278,7 @@ void ulp_stack_helper(void)
     /* In this case the system is out of memory...  And there is nothing
        we can do.  */
     libpulp_crash("libpulp: mmap returned -1, application can not continue\n");
-    return;
+    return ulp_stack;
   }
 
   /* In case we have a previous allocated buffer, then copy this.  */
@@ -304,4 +306,6 @@ void ulp_stack_helper(void)
   /* Setup destructor for mmap memory, so we don't leak memory when a thread
      is destroyed.  */
   pthread_once(&ulp_once_control, ulp_pthread_key_init);
+
+  return ulp_stack;
 }
diff --git a/lib/arch/powerpc64le/ulp_prologue.S b/lib/arch/powerpc64le/ulp_prologue.S
index 895638c4..e0d07e88 100644
--- a/lib/arch/powerpc64le/ulp_prologue.S
+++ b/lib/arch/powerpc64le/ulp_prologue.S
@@ -32,6 +32,10 @@
 .globl   ulp_stack_helper
 .type    ulp_stack_helper, @function
 
+# __tls_get_addr
+.globl   __tls_get_addr
+.type    __tls_get_addr, @function
+
 .section        ".text"
 .align 2
 .p2align 4,,15
@@ -40,7 +44,7 @@
 .globl   trampoline_routine
 .type    trampoline_routine, @function
 trampoline_routine:
-	.cfi_startproc
+  .cfi_startproc
 
   # Concatenate two registers from prologue.
   rldimi %r6, %r5, 32, 0
@@ -48,36 +52,67 @@ trampoline_routine:
   # Move the target function ptr to control register so we can free r6.
   mtctr %r6
 
-  # Load the ulp_stack into r5 through r13 (thread local storage ptr)
-  addis %r5, %r13, ulp_stack@tprel@ha
-  addi  %r5, %r5,  ulp_stack@tprel@l
+  # Save all volatile registers
+  # r5 & r6 are designated temp regs, having data already on stack.
+  # After return from expand_ulp_stack, both regs construct values
+  # before use.
+  std   %r2,  -24(%r1)
+  std   %r3,  -32(%r1)
+  std   %r12, -40(%r1)
+  mflr  %r2
+  std   %r2,  -48(%r1)
+
+  # Move stack register
+  addi  %r1, %r1, -(48 + 32 + 8) # 32 + 8 for padding
+
+  # Fix TOC.  %r12 must be pointing to the address of trampoline_routine.
+  addis %r2,%r12, .TOC.-trampoline_routine@ha
+  addi  %r2,%r2 , .TOC.-trampoline_routine@l
+
+  # Load ulp_stack
+  addis %r3, %r2, ulp_stack@got@tlsgd@ha
+  addi  %r3, %r3, ulp_stack@got@tlsgd@l
 
-  # Load real_size
-  ld    %r6, ULP_STACK_REAL_SIZE(%r5)   # Load real_size (allocated by mmap)
-  ld    %r5, ULP_STACK_USED_SIZE(%r5)   # Load used_size (currently in use)
+  # Get address of ulp_stack
+  bl    __tls_get_addr(ulp_stack@tlsgd)
+  nop
 
-  # Check if we have space.
-  cmpd %cr0, %r6, %r5
+  # Load ulp_stack attributes
+  ld    %r6, ULP_STACK_REAL_SIZE(%r3)     # Load real_size (allocated by mmap)
+  ld    %r5, ULP_STACK_USED_SIZE(%r3)     # Load used_size
+
+  # Check if we have space
+  cmpd  %cr0, %r6, %r5
   ble   %cr0, .Lexpand_ulp_stack
 
 .Lcontinue_ulp_prologue:
 
-  # Reload the ulp_stack into r5 through r13 (thread local storage ptr)
-  addis %r5, %r13, ulp_stack@tprel@ha
-  addi  %r5, %r5,  ulp_stack@tprel@l
+  # Here we must ensure that %r3 points to ulp_stack.  If we are here from
+  # the .Lexpand_ulp_stack, then r3 will point to it because
+  # ulp_stack_helper returned it.
 
   # Load used_size
-  ld    %r6, ULP_STACK_USED_SIZE(%r5)
+  ld    %r6, ULP_STACK_USED_SIZE(%r3)
 
   # Update top_of_stack in the struct field.
   addi  %r6, %r6, 16
-  std   %r6, ULP_STACK_USED_SIZE(%r5)    # Store new used size value.
+  std   %r6, ULP_STACK_USED_SIZE(%r3)    # Store new used size value.
 
   # Load stack ptr
-  ld    %r5, ULP_STACK_PTR(%r5)
+  ld    %r5, ULP_STACK_PTR(%r3)
 
   # Store TOC
-  add   %r5, %r5, %r6  # ulp_stack + used_size
+  add   %r5, %r5, %r6  # ulp_stack_ptr + used_size
+
+  # Restore stack register.
+  addi  %r1, %r1, (48 + 32 + 8)
+
+  # Load original LR
+  ld    %r2, -48(%r1)
+  mtlr  %r2
+
+  # Load original TOC
+  ld    %r6, -24(%r1)
 
   # At this point, %r5 points to 16 bytes ahead of the slot where we shall
   # save TOC.  Hence we have to subtract 16 bytes of the storing location,
@@ -86,29 +121,55 @@ trampoline_routine:
   # +----------------------------------v
   # | TOC1 | LR1 || ... || _8b_ | _8b_ |
   # +----------------------------------+
-  std   %r2, -16(%r5)  # store in *(ulp_stack + used_size - 16)
-  mflr  %r2
+  std   %r6, -16(%r5)  # store in *(ulp_stack + used_size - 16)
   std   %r2, -8(%r5)   # store in *(ulp_stack + used_size - 8)
 
+
   # Restore registers
-  ld    %r5, -8(%r1)  # Restore register.
-  ld    %r6, -16(%r1) # Restore register.
+  ld    %r5, -8(%r1)   # Restore register.
+  ld    %r6, -16(%r1)  # Restore register.
+ #ld    %r2,  -24(%r1) # r2 was already loaded
+  ld    %r3,  -32(%r1)
+  ld    %r12, -40(%r1)
 
-  # Jump to target function
+  # jump to target function
   mfctr %r12
   bctrl
 
-  # Load the ulp_stack into r5 through r13 (thread local storage ptr)
-  addis %r5, %r13, ulp_stack@tprel@ha
-  addi  %r5, %r5,  ulp_stack@tprel@l
+  # Save return registers and ones used by __get_tls_addr.
+  std   %r3,  -8(%r1)
+  std   %r12, -16(%r1)
+
+  # Move stack register
+  addi  %r1, %r1, -(16 + 32 + 8) # 32 + 8 for padding
+
+  # Do a trick to load PC into LR register.
+  bl    .return_to_caller
+.return_to_caller:
+  mflr  %r12
+
+  # Get the function address.
+  addi  %r12, %r12, trampoline_routine - .return_to_caller
+
+  # Fix TOC.  %r12 must be pointing to the address of trampoline_routine.
+  addis %r2,%r12, .TOC.-trampoline_routine@ha
+  addi  %r2,%r2 , .TOC.-trampoline_routine@l
+
+  # Load ulp_stack
+  addis %r3, %r2, ulp_stack@got@tlsgd@ha
+  addi  %r3, %r3, ulp_stack@got@tlsgd@l
+
+  # Get address of ulp_stack
+  bl    __tls_get_addr(ulp_stack@tlsgd)
+  nop
 
   # Deference ulp_stack.
-  ld    %r6, ULP_STACK_USED_SIZE(%r5)
+  ld    %r6, ULP_STACK_USED_SIZE(%r3)
   addi  %r6, %r6, -16   # Sub 16 bytes because the first entry stores the top of stack, and we need to store 2 longs.
-  std   %r6, ULP_STACK_USED_SIZE(%r5)     # Store new used_size value.
+  std   %r6, ULP_STACK_USED_SIZE(%r3)     # Store new used_size value.
 
   # Load ulp_stack ptr field.
-  ld    %r5, ULP_STACK_PTR(%r5)
+  ld    %r5, ULP_STACK_PTR(%r3)
 
   # Point to the top of stack but two, these two entries are popped in
   # previous step and accessed in next step (stack size decremented before access).
@@ -119,64 +180,55 @@ trampoline_routine:
   ld    %r8, 8(%r5)     # Restore LR
   mtlr  %r8             # Load LR
 
-  # Return execution to caller.
+  # Restore used registers
+  addi  %r1, %r1, (16 + 32 + 8) # 32 + 8 for padding
+  ld    %r3,  -8(%r1)
+  ld    %r12, -16(%r1)
+
+  # Return.
   blr
 
 .Lexpand_ulp_stack:
 
   # Save all volatile registers
   # r5 & r6 are designated temp regs, having data already on stack.
+  # r0, r2 & r12 is as well in this slow path.
   # After return from expand_ulp_stack, both regs construct values
   # before use.
-  std   %r2,  -24(%r1)
-  std   %r3,  -32(%r1)
-  std   %r4,  -40(%r1)
-  std   %r7,  -48(%r1)
-  std   %r8,  -56(%r1)
-  std   %r9,  -64(%r1)
-  std   %r10, -72(%r1)
-  std   %r11, -80(%r1)
-  std   %r12, -88(%r1)
-  mfctr %r3
-  std   %r3,  -96(%r1)
-  mflr  %r3,
-  std   %r3,  -104(%r1)
-
-  # As per ppc64le ABIv2, the minimum stack frame is of 32 bytes and
-  # additional 8 bytes padding is needed for alignment in stack frame.
-  # The regs stored in redzone must have this 32+8 bytes padding to form
-  # auxiliary stack frame before calling ulp_stack_helper which will
-  # have its own proper stack frame.
-
-  # Move stack register
-  addi  %r1, %r1, -(104 + 32 + 8) # 32 + 8 for padding
-
-  # Fix TOC.  %r12 must be pointing to the address of trampoline_routine.
-  addis %r2,%r12, .TOC.-trampoline_routine@ha
-  addi  %r2,%r2 , .TOC.-trampoline_routine@l
+  std   %r4,  -8(%r1)
+  std   %r7,  -16(%r1)
+  std   %r8,  -24(%r1)
+  std   %r9,  -32(%r1)
+  std   %r10, -40(%r1)
+  std   %r11, -48(%r1)
+  mfctr %r4
+  std   %r4,  -56(%r1)
+  mflr  %r4,
+  std   %r4,  -64(%r1)
+
+  # Setup stack frame
+  addi  %r1, %r1, -(64 + 32 + 8)
 
   # Call C helper routine.
-  bl ulp_stack_helper
+  bl    ulp_stack_helper
   nop
 
-  # Restore stack register.
-  addi  %r1, %r1, (104 + 32 + 8)
-
-  # Restore registers
-  ld    %r3,  -104(%r1)
-  mtlr  %r3
-  ld    %r3,  -96(%r1)
-  mtctr %r3
-  ld    %r12, -88(%r1)
-  ld    %r11, -80(%r1)
-  ld    %r10, -72(%r1)
-  ld    %r9,  -64(%r1)
-  ld    %r8,  -56(%r1)
-  ld    %r7,  -48(%r1)
-  ld    %r4,  -40(%r1)
-  ld    %r3,  -32(%r1)
-  ld    %r2,  -24(%r1)
-
+  # Restore stack frame
+  addi %r1, %r1, (64 + 32 + 8)
+
+  # Load back registers.
+  ld    %r7,  -16(%r1)
+  ld    %r8,  -24(%r1)
+  ld    %r9,  -32(%r1)
+  ld    %r10, -40(%r1)
+  ld    %r11, -48(%r1)
+  ld    %r4,  -56(%r1)
+  mtctr %r4
+  ld    %r4,  -64(%r1)
+  mtlr  %r4
+  ld    %r4,  -8(%r1)
+
+  # Continue execution
   b     .Lcontinue_ulp_prologue
 
 	.long 0
@@ -184,8 +236,12 @@ trampoline_routine:
 	.cfi_endproc
 	.size	trampoline_routine,.-trampoline_routine
 
-	.globl ulp_prologue
-	.type  ulp_prologue, @function
+# The following function needs to be placed in .data, as it is a template to be
+# copied in the prologue of tha patched function.  Placing this in .data avoids
+# text relocations.
+.section        ".data"
+.globl ulp_prologue
+.type  ulp_prologue, @function
 ulp_prologue:
 	.cfi_startproc
   std   %r5, -8(%r1)  # Save one register used as function parameter
@@ -195,7 +251,7 @@ ulp_prologue:
   lis   %r5,  trampoline_routine@highest     #0x1122
   ori   %r5,  %r5, trampoline_routine@higher #0x3344
   lis   %r12, trampoline_routine@high        #0x5566
-  ori   %r12, %r12, trampoline_routine@l      #0x7788
+  ori   %r12, %r12, trampoline_routine@l     #0x7788
 
   # Concatenate two registers
   rldimi %r12, %r5, 32, 0
@@ -223,7 +279,7 @@ ulp_prologue_end = .
 	.size ulp_prologue,.-ulp_prologue
 ulp_prologue_padding_end = .
 
-.section      ".data"
+.section      ".rodata"
 .align        2
 .type         ulp_prologue_size, @object
 .size         ulp_prologue_size, 4
diff --git a/tests/Makefile.am b/tests/Makefile.am
index bbca5ab8..ad6a70d1 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -695,7 +695,8 @@ TESTS = \
   insn_queue.py \
   chroot.py \
   visibility.py \
-  notes.py
+  notes.py \
+  textrel.py
 
 XFAIL_TESTS = \
   blocked.py \
diff --git a/tests/testsuite.py b/tests/testsuite.py
index 4e4ba4ae..a9c3362e 100755
--- a/tests/testsuite.py
+++ b/tests/testsuite.py
@@ -39,6 +39,7 @@
 # Libpulp definitions
 builddir = os.getcwd()
 ulptool = builddir + '/../tools/ulp'
+libpulp_path = builddir + '/../lib/.libs/libpulp.so'
 
 # Check if certain library is livepatchable.
 def is_library_livepatchable(library):
@@ -116,7 +117,7 @@ def __init__(self, testname, timeout=10, env=Ellipsis, log=sys.stdout,
 
     # If env has not been provided, default to LD_PRELOAD'ing libpulp.so.
     if env == Ellipsis:
-      env = {'LD_PRELOAD': builddir + '/../lib/.libs/libpulp.so'}
+      env = {'LD_PRELOAD': libpulp_path}
 
     # Spawn the testcase with pexpect and enable logging.
     super().__init__(testname, timeout=timeout, env=env, encoding=encoding,
diff --git a/tests/textrel.py b/tests/textrel.py
new file mode 100644
index 00000000..b9e36b23
--- /dev/null
+++ b/tests/textrel.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python3
+
+#   libpulp - User-space Livepatching Library
+#
+#   Copyright (C) 2020-2025 SUSE Software Solutions GmbH
+#
+#   This file is part of libpulp.
+#
+#   libpulp is free software; you can redistribute it and/or
+#   modify it under the terms of the GNU Lesser General Public
+#   License as published by the Free Software Foundation; either
+#   version 2.1 of the License, or (at your option) any later version.
+#
+#   libpulp is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#   Lesser General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with libpulp.  If not, see <http://www.gnu.org/licenses/>.
+
+import re
+import testsuite
+import subprocess
+
+# Make sure libpulp is built without TEXTREL.
+
+command = ['readelf', '-d', testsuite.libpulp_path]
+try:
+  output = subprocess.check_output(command, timeout=10, stderr=subprocess.STDOUT)
+  textrel = re.search('TEXTREL', output.decode())
+  if not textrel:
+    exit(0)
+
+except subprocess.TimeoutExpired:
+  print('readelf timeout')
+  exit(77)
+
+exit(1)


Reviews:
user: login: susematz
body: Okay to merge either way, with the r2-save/restore adjustment or not.
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-04-03T14:31:13Z
user: login: giulianobelinassi
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-03T15:56:21Z
user: login: susematz
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-03T16:24:42Z

Review comments:
diff_hunk: @@ -40,44 +44,75 @@
 .globl   trampoline_routine
 .type    trampoline_routine, @function
 trampoline_routine:
-	.cfi_startproc
+  .cfi_startproc
 
   # Concatenate two registers from prologue.
   rldimi %r6, %r5, 32, 0
 
   # Move the target function ptr to control register so we can free r6.
   mtctr %r6
 
-  # Load the ulp_stack into r5 through r13 (thread local storage ptr)
-  addis %r5, %r13, ulp_stack@tprel@ha
-  addi  %r5, %r5,  ulp_stack@tprel@l
+  # Save all volatile registers
+  # r5 & r6 are designated temp regs, having data already on stack.
+  # After return from expand_ulp_stack, both regs construct values
+  # before use.
+  std   %r2,  -24(%r1)
+  std   %r3,  -32(%r1)
+  std   %r12, -40(%r1)
+  mflr  %r2
+  std   %r2,  -48(%r1)
+
+  # Move stack register
+  addi  %r1, %r1, -(48 + 32 + 8) # 32 + 8 for padding
+
+  # Fix TOC.  %r12 must be pointing to the address of trampoline_routine.
+  addis %r2,%r12, .TOC.-trampoline_routine@ha
+  addi  %r2,%r2 , .TOC.-trampoline_routine@l
+
+  # Load ulp_stack
+  addis %r3, %r2, ulp_stack@got@tlsgd@ha
+  addi  %r3, %r3, ulp_stack@got@tlsgd@l
 
path: lib/arch/powerpc64le/ulp_prologue.S
user: login: susematz
body: I think you're not using this %r2 later (i.e. the TOC pointer here).  If this is really so, you could spare one regsave/restore by directly constructing the TOC into %r3 (and then update it with the ulp_stack@got offset),
instead of via %r2.  Another instance of that is below.  Also, is the save/restore of %r12 needed, you don't save/restore it in the original code, and don't change it for calling tls_get_addr, so perhaps it doesn't need saving?
created_at: 2025-04-03T14:28:49Z
author_association: COLLABORATOR
diff_hunk: @@ -40,44 +44,75 @@
 .globl   trampoline_routine
 .type    trampoline_routine, @function
 trampoline_routine:
-	.cfi_startproc
+  .cfi_startproc
 
   # Concatenate two registers from prologue.
   rldimi %r6, %r5, 32, 0
 
   # Move the target function ptr to control register so we can free r6.
   mtctr %r6
 
-  # Load the ulp_stack into r5 through r13 (thread local storage ptr)
-  addis %r5, %r13, ulp_stack@tprel@ha
-  addi  %r5, %r5,  ulp_stack@tprel@l
+  # Save all volatile registers
+  # r5 & r6 are designated temp regs, having data already on stack.
+  # After return from expand_ulp_stack, both regs construct values
+  # before use.
+  std   %r2,  -24(%r1)
+  std   %r3,  -32(%r1)
+  std   %r12, -40(%r1)
+  mflr  %r2
+  std   %r2,  -48(%r1)
+
+  # Move stack register
+  addi  %r1, %r1, -(48 + 32 + 8) # 32 + 8 for padding
+
+  # Fix TOC.  %r12 must be pointing to the address of trampoline_routine.
+  addis %r2,%r12, .TOC.-trampoline_routine@ha
+  addi  %r2,%r2 , .TOC.-trampoline_routine@l
+
+  # Load ulp_stack
+  addis %r3, %r2, ulp_stack@got@tlsgd@ha
+  addi  %r3, %r3, ulp_stack@got@tlsgd@l
 
path: lib/arch/powerpc64le/ulp_prologue.S
user: login: giulianobelinassi
body: TOC should be setup correctly in %r2 for `__tls_get_addr` to work and it will return the `ulp_stack` address on %r3. Just to be sure I tried this now and tests began to fail. 
created_at: 2025-04-03T15:56:21Z
author_association: COLLABORATOR
diff_hunk: @@ -40,44 +44,75 @@
 .globl   trampoline_routine
 .type    trampoline_routine, @function
 trampoline_routine:
-	.cfi_startproc
+  .cfi_startproc
 
   # Concatenate two registers from prologue.
   rldimi %r6, %r5, 32, 0
 
   # Move the target function ptr to control register so we can free r6.
   mtctr %r6
 
-  # Load the ulp_stack into r5 through r13 (thread local storage ptr)
-  addis %r5, %r13, ulp_stack@tprel@ha
-  addi  %r5, %r5,  ulp_stack@tprel@l
+  # Save all volatile registers
+  # r5 & r6 are designated temp regs, having data already on stack.
+  # After return from expand_ulp_stack, both regs construct values
+  # before use.
+  std   %r2,  -24(%r1)
+  std   %r3,  -32(%r1)
+  std   %r12, -40(%r1)
+  mflr  %r2
+  std   %r2,  -48(%r1)
+
+  # Move stack register
+  addi  %r1, %r1, -(48 + 32 + 8) # 32 + 8 for padding
+
+  # Fix TOC.  %r12 must be pointing to the address of trampoline_routine.
+  addis %r2,%r12, .TOC.-trampoline_routine@ha
+  addi  %r2,%r2 , .TOC.-trampoline_routine@l
+
+  # Load ulp_stack
+  addis %r3, %r2, ulp_stack@got@tlsgd@ha
+  addi  %r3, %r3, ulp_stack@got@tlsgd@l
 
path: lib/arch/powerpc64le/ulp_prologue.S
user: login: susematz
body: Ah, I see.  Well then, merge it :)
created_at: 2025-04-03T16:24:42Z
author_association: COLLABORATOR

PR comments:
user: login: giulianobelinassi
created_at: 2025-04-02T20:11:36Z
body: @dubeyabhishek Can you also take a look at this? This should fix bsc#1239092.
author_association: COLLABORATOR
user: login: susematz
created_at: 2025-04-03T14:20:13Z
body: So, you haven't found a way to make it work without calling __tls_get_addr?  E.g. by using the local dynamic or initial exec TLS model?  Anyway, I guess correctness comes first, so either way this is an improvement.
author_association: COLLABORATOR
user: login: giulianobelinassi
created_at: 2025-04-03T14:23:09Z
body: > So, you haven't found a way to make it work without calling __tls_get_addr? E.g. by using the local dynamic or initial exec TLS model? Anyway, I guess correctness comes first, so either way this is an improvement.

local dynamic generates the same code as it previously did, e.g. with TEXTRELs. initial-exec gave me link errors about it not being able to optimize the `ulp_stack` accesses, so there was no other option than call `__tls_get_addr`...
author_association: COLLABORATOR
user: login: susematz
created_at: 2025-04-03T14:33:29Z
body: > local dynamic generates the same code as it previously did, e.g. with TEXTRELs. initial-exec gave me link errors about it not being able to optimize the `ulp_stack` accesses, so there was no other option than call `__tls_get_addr`...

Hmm, have you marked ulp_stack as hidden?  Anyway, any optimization of this sequence can be done as followup.
author_association: COLLABORATOR
user: login: giulianobelinassi
created_at: 2025-04-03T15:35:54Z
body: > > local dynamic generates the same code as it previously did, e.g. with TEXTRELs. initial-exec gave me link errors about it not being able to optimize the `ulp_stack` accesses, so there was no other option than call `__tls_get_addr`...
> 
> Hmm, have you marked ulp_stack as hidden? Anyway, any optimization of this sequence can be done as followup.

hidden as in `__attribute__((hidden))`, and then copy-and-pasting the asm code? Yes, that did not change anything.

In any case, I will check if the dynamic linker is able to optimize any of those calls. If yes I will copy-and-paste whatever code it generated.
author_association: COLLABORATOR
user: login: giulianobelinassi
created_at: 2025-04-03T16:15:12Z
body: > > > local dynamic generates the same code as it previously did, e.g. with TEXTRELs. initial-exec gave me link errors about it not being able to optimize the `ulp_stack` accesses, so there was no other option than call `__tls_get_addr`...
> > 
> > 
> > Hmm, have you marked ulp_stack as hidden? Anyway, any optimization of this sequence can be done as followup.
> 
> hidden as in `__attribute__((hidden))`, and then copy-and-pasting the asm code? Yes, that did not change anything.
> 
> In any case, I will check if the dynamic linker is able to optimize any of those calls. If yes I will copy-and-paste whatever code it generated.

Looking at the code the linker generated we see:
```
B+>0x7fff8d809620 <trampoline_routine>     rldimi  r6,r5,32,0
   0x7fff8d809624 <trampoline_routine+4>   mtctr   r6
   0x7fff8d809628 <trampoline_routine+8>   std     r2,-24(r1)
   0x7fff8d80962c <trampoline_routine+12>  std     r3,-32(r1)
   0x7fff8d809630 <trampoline_routine+16>  std     r12,-40(r1)
   0x7fff8d809634 <trampoline_routine+20>  mflr    r2
   0x7fff8d809638 <trampoline_routine+24>  std     r2,-48(r1)
   0x7fff8d80963c <trampoline_routine+28>  addi    r1,r1,-88
   0x7fff8d809640 <trampoline_routine+32>  addis   r2,r12,2
   0x7fff8d809644 <trampoline_routine+36>  addi    r2,r2,-5920
   0x7fff8d809648 <trampoline_routine+40>  nop
   0x7fff8d80964c <trampoline_routine+44>  addi    r3,r2,-32592
   0x7fff8d809650 <trampoline_routine+48>  bl      0x7fff8d8026a0 <00000046.plt_call.__tls_get_addr_opt@@GLIBC_2.22>
   0x7fff8d809654 <trampoline_routine+52>  nop
   0x7fff8d809658 <trampoline_routine+56>  ld      r6,0(r3)
   0x7fff8d80965c <trampoline_routine+60>  ld      r5,8(r3)
   0x7fff8d809660 <trampoline_routine+64>  cmpd    r6,r5
   0x7fff8d809664 <trampoline_routine+68>  ble     0x7fff8d80970c <trampoline_routine+236>
   0x7fff8d809668 <trampoline_routine+72>  ld      r6,8(r3)
   0x7fff8d80966c <trampoline_routine+76>  addi    r6,r6,16
   0x7fff8d809670 <trampoline_routine+80>  std     r6,8(r3)
   0x7fff8d809674 <trampoline_routine+84>  ld      r5,16(r3)
   0x7fff8d809678 <trampoline_routine+88>  add     r5,r5,r6
   0x7fff8d80967c <trampoline_routine+92>  addi    r1,r1,88
   0x7fff8d809680 <trampoline_routine+96>  ld      r2,-48(r1)
   0x7fff8d809684 <trampoline_routine+100> mtlr    r2
   0x7fff8d809688 <trampoline_routine+104> ld      r6,-24(r1)
   0x7fff8d80968c <trampoline_routine+108> std     r6,-16(r5)
   0x7fff8d809690 <trampoline_routine+112> std     r2,-8(r5)
   0x7fff8d809694 <trampoline_routine+116> ld      r5,-8(r1)
   0x7fff8d809698 <trampoline_routine+120> ld      r6,-16(r1)
```
Hence, no optimization on __tls_get_addr. So I double checked if gcc generates any code if `__attribute__((hidden))` is passed to `ulp_stack` or not and the resulting .s diff shows no differences.

So both gcc or ldd is not able to optimize this.
author_association: COLLABORATOR
user: login: susematz
created_at: 2025-04-03T16:27:08Z
body: > > > local dynamic generates the same code as it previously did, e.g. with TEXTRELs. initial-exec gave me link errors about it not being able to optimize the `ulp_stack` accesses, so there was no other option than call `__tls_get_addr`...
> > 
> > 
> > Hmm, have you marked ulp_stack as hidden? Anyway, any optimization of this sequence can be done as followup.
> 
> hidden as in `__attribute__((hidden))`, and then copy-and-pasting the asm code? Yes, that did not change anything.

Yeah, that's what I meant (or making ulp_stack[] come from the same file and marked static).  I now see that that
doesn't avoid __tls_get_addr either (the link editor will rewrite the sequence somewhat, but not remove the call).
Too bad then :)

author_association: COLLABORATOR
user: login: dubeyabhishek
created_at: 2025-04-04T11:40:11Z
body: > @dubeyabhishek Can you also take a look at this? This should fix bsc#1239092.

The system is booting fine with this patch and libpulp-load-default installed.
author_association: CONTRIBUTOR