public inbox for elfutils@sourceware.org
 help / color / mirror / Atom feed
* Compile elfutils with Clang
@ 2017-09-09 10:53 Dmitry Golovin
       [not found] ` <CAEk9T_1jS-JmN6Ef+5ncsGodgK4oT7FwAu9C5PZCgoPJFPhcNg@mail.gmail.com>
  2017-09-19 14:27 ` Mark Wielaard
  0 siblings, 2 replies; 5+ messages in thread
From: Dmitry Golovin @ 2017-09-09 10:53 UTC (permalink / raw)
  To: chh, elfutils-devel

Hello,

I've been trying to compile elfutils with clang for a while now and I'm wondering maybe someone else is also working on it?
I found some useful patches written by Chih-Hung Hsieh, but they seem to be written over 2 years ago and not maintained.
Is there a fork or a branch of elfutils that can be compiled with clang?

Regards,
Dmitry

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Compile elfutils with Clang
       [not found] ` <CAEk9T_1jS-JmN6Ef+5ncsGodgK4oT7FwAu9C5PZCgoPJFPhcNg@mail.gmail.com>
@ 2017-09-12 13:09   ` Dmitry Golovin
  2017-09-12 14:32     ` Ulf Hermann
  0 siblings, 1 reply; 5+ messages in thread
From: Dmitry Golovin @ 2017-09-12 13:09 UTC (permalink / raw)
  To: Chih-hung Hsieh; +Cc: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 958 bytes --]

Hi Chih-hung,
 
I have added clang support to elfutils 0.170, the work is mostly based on your patches. So I'm attaching it and posting it to the mailing list in case someone else wants to compile it with clang.

(sending it again, because the first message was not accepted by the mailing list contene filter)
 
Regards,
Dmitry

11.09.2017, 19:34, "Chih-hung Hsieh" <chh@google.com>:
> Dimitry, I made a few changes to compile some libraries in elfutils that were needed by Android.
> I don't have a separate branch.
>
> On Sat, Sep 9, 2017 at 3:52 AM, Dmitry Golovin <dima@golovin.in> wrote:
>> Hello,
>>
>> I've been trying to compile elfutils with clang for a while now and I'm wondering maybe someone else is also working on it?
>> I found some useful patches written by Chih-Hung Hsieh, but they seem to be written over 2 years ago and not maintained.
>> Is there a fork or a branch of elfutils that can be compiled with clang?
>>
>> Regards,
>> Dmitry

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: clang-support.patch --]
[-- Type: text/x-diff; name="clang-support.patch", Size: 47810 bytes --]

diff --git a/libdwfl/dwfl_segment_report_module.c b/libdwfl/dwfl_segment_report_module.c
index 207a257..c3d7f88 100644
--- a/libdwfl/dwfl_segment_report_module.c
+++ b/libdwfl/dwfl_segment_report_module.c
@@ -31,6 +31,7 @@
 #undef	_
 #include "libdwflP.h"
 #include "common.h"
+#include "nested_func.h"
 
 #include <elf.h>
 #include <gelf.h>
@@ -233,15 +234,18 @@ invalid_elf (Elf *elf, bool disk_file_has_build_id,
 }
 
 int
-dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
-			    Dwfl_Memory_Callback *memory_callback,
-			    void *memory_callback_arg,
-			    Dwfl_Module_Callback *read_eagerly,
-			    void *read_eagerly_arg,
-			    const void *note_file, size_t note_file_size,
-			    const struct r_debug_info *r_debug_info)
+dwfl_segment_report_module (Dwfl *dwfl, int const ndx_in, const char* const name_in,
+			    Dwfl_Memory_Callback* const memory_callback,
+			    void* const memory_callback_arg,
+			    Dwfl_Module_Callback * const read_eagerly,
+			    void* const read_eagerly_arg,
+			    const void* const note_file, size_t const note_file_size,
+			    const struct r_debug_info* const r_debug_info)
 {
-  size_t segment = ndx;
+  __BLOCK int ndx = ndx_in;
+  __BLOCK const char *name = name_in;
+
+  __BLOCK size_t segment = ndx;
 
   if (segment >= dwfl->lookup_elts)
     segment = dwfl->lookup_elts - 1;
@@ -255,34 +259,38 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
     if (++segment == dwfl->lookup_elts)
       return 0;
 
-  GElf_Addr start = dwfl->lookup_addr[segment];
+  __BLOCK GElf_Addr start = dwfl->lookup_addr[segment];
 
-  inline bool segment_read (int segndx,
-			    void **buffer, size_t *buffer_available,
-			    GElf_Addr addr, size_t minread)
+  INLINE_NESTED_FUNC (bool, segment_read,
+                      (int , void **, size_t *, GElf_Addr, size_t),
+                      (int segndx,
+                       void **buffer, size_t *buffer_available,
+                       GElf_Addr addr, size_t minread))
   {
     return ! (*memory_callback) (dwfl, segndx, buffer, buffer_available,
 				 addr, minread, memory_callback_arg);
-  }
+  };
 
-  inline void release_buffer (void **buffer, size_t *buffer_available)
+  INLINE_NESTED_FUNC (void, release_buffer,
+                      (void **, size_t *),
+                      (void **buffer, size_t *buffer_available))
   {
     if (*buffer != NULL)
       (void) segment_read (-1, buffer, buffer_available, 0, 0);
-  }
+  };
 
   /* First read in the file header and check its sanity.  */
 
-  void *buffer = NULL;
-  size_t buffer_available = INITIAL_READ;
-  Elf *elf = NULL;
-  int fd = -1;
+  __BLOCK void *buffer = NULL;
+  __BLOCK size_t buffer_available = INITIAL_READ;
+  __BLOCK Elf *elf = NULL;
+  __BLOCK int fd = -1;
 
   /* We might have to reserve some memory for the phdrs.  Set to NULL
      here so we can always safely free it.  */
-  void *phdrsp = NULL;
+  __BLOCK void *phdrsp = NULL;
 
-  inline int finish (void)
+  INLINE_NESTED_FUNC (int, finish, (void), (void))
   {
     free (phdrsp);
     release_buffer (&buffer, &buffer_available);
@@ -291,15 +299,17 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
     if (fd != -1)
       close (fd);
     return ndx;
-  }
+  };
 
   if (segment_read (ndx, &buffer, &buffer_available,
 		    start, sizeof (Elf64_Ehdr))
       || memcmp (buffer, ELFMAG, SELFMAG) != 0)
     return finish ();
 
-  inline bool read_portion (void **data, size_t *data_size,
-			    GElf_Addr vaddr, size_t filesz)
+  INLINE_NESTED_FUNC (bool, read_portion,
+                      (void **, size_t *, GElf_Addr, size_t),
+                      (void **data, size_t *data_size,
+                       GElf_Addr vaddr, size_t filesz))
   {
     if (vaddr - start + filesz > buffer_available
 	/* If we're in string mode, then don't consider the buffer we have
@@ -317,35 +327,37 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
     *data = vaddr - start + buffer;
     *data_size = 0;
     return false;
-  }
+  };
 
-  inline void finish_portion (void **data, size_t *data_size)
+  INLINE_NESTED_FUNC (void, finish_portion,
+                      (void **, size_t *),
+                      (void **data, size_t *data_size))
   {
     if (*data_size != 0)
       release_buffer (data, data_size);
-  }
+  };
 
   /* Extract the information we need from the file header.  */
-  const unsigned char *e_ident;
-  unsigned char ei_class;
-  unsigned char ei_data;
-  uint16_t e_type;
-  union
+  __BLOCK const unsigned char *e_ident;
+  __BLOCK unsigned char ei_class;
+  __BLOCK unsigned char ei_data;
+  __BLOCK uint16_t e_type;
+  __BLOCK union
   {
     Elf32_Ehdr e32;
     Elf64_Ehdr e64;
   } ehdr;
-  GElf_Off phoff;
-  uint_fast16_t phnum;
-  uint_fast16_t phentsize;
-  GElf_Off shdrs_end;
-  Elf_Data xlatefrom =
+  __BLOCK GElf_Off phoff;
+  __BLOCK uint_fast16_t phnum;
+  __BLOCK uint_fast16_t phentsize;
+  __BLOCK GElf_Off shdrs_end;
+  __BLOCK Elf_Data xlatefrom =
     {
       .d_type = ELF_T_EHDR,
       .d_buf = (void *) buffer,
       .d_version = EV_CURRENT,
     };
-  Elf_Data xlateto =
+  __BLOCK Elf_Data xlateto =
     {
       .d_type = ELF_T_EHDR,
       .d_buf = &ehdr,
@@ -397,8 +409,8 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
   xlatefrom.d_type = xlateto.d_type = ELF_T_PHDR;
   xlatefrom.d_size = phnum * phentsize;
 
-  void *ph_buffer = NULL;
-  size_t ph_buffer_size = 0;
+  __BLOCK void *ph_buffer = NULL;
+  __BLOCK size_t ph_buffer_size = 0;
   if (read_portion (&ph_buffer, &ph_buffer_size,
 		    start + phoff, xlatefrom.d_size))
     return finish ();
@@ -418,31 +430,33 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
   xlateto.d_size = phdrsp_bytes;
 
   /* Track the bounds of the file visible in memory.  */
-  GElf_Off file_trimmed_end = 0; /* Proper p_vaddr + p_filesz end.  */
-  GElf_Off file_end = 0;	 /* Rounded up to effective page size.  */
-  GElf_Off contiguous = 0;	 /* Visible as contiguous file from START.  */
-  GElf_Off total_filesz = 0;	 /* Total size of data to read.  */
+  __BLOCK GElf_Off file_trimmed_end = 0; /* Proper p_vaddr + p_filesz end.  */
+  __BLOCK GElf_Off file_end = 0;	 /* Rounded up to effective page size.  */
+  __BLOCK GElf_Off contiguous = 0;	 /* Visible as contiguous file from START.  */
+  __BLOCK GElf_Off total_filesz = 0;	 /* Total size of data to read.  */
 
   /* Collect the bias between START and the containing PT_LOAD's p_vaddr.  */
-  GElf_Addr bias = 0;
-  bool found_bias = false;
+  __BLOCK GElf_Addr bias = 0;
+  __BLOCK bool found_bias = false;
 
   /* Collect the unbiased bounds of the module here.  */
-  GElf_Addr module_start = -1l;
-  GElf_Addr module_end = 0;
-  GElf_Addr module_address_sync = 0;
+  __BLOCK GElf_Addr module_start = -1l;
+  __BLOCK GElf_Addr module_end = 0;
+  __BLOCK GElf_Addr module_address_sync = 0;
 
   /* If we see PT_DYNAMIC, record it here.  */
-  GElf_Addr dyn_vaddr = 0;
-  GElf_Xword dyn_filesz = 0;
+  __BLOCK GElf_Addr dyn_vaddr = 0;
+  __BLOCK GElf_Xword dyn_filesz = 0;
 
   /* Collect the build ID bits here.  */
-  void *build_id = NULL;
-  size_t build_id_len = 0;
-  GElf_Addr build_id_vaddr = 0;
+  __BLOCK void *build_id = NULL;
+  __BLOCK size_t build_id_len = 0;
+  __BLOCK GElf_Addr build_id_vaddr = 0;
 
   /* Consider a PT_NOTE we've found in the image.  */
-  inline void consider_notes (GElf_Addr vaddr, GElf_Xword filesz)
+  INLINE_NESTED_FUNC (void, consider_notes,
+                      (GElf_Addr, GElf_Xword),
+                      (GElf_Addr vaddr, GElf_Xword filesz))
   {
     /* If we have already seen a build ID, we don't care any more.  */
     if (build_id != NULL || filesz == 0)
@@ -502,13 +516,18 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
     if (notes != data)
       free (notes);
     finish_portion (&data, &data_size);
-  }
+  };
 
   /* Consider each of the program headers we've read from the image.  */
-  inline void consider_phdr (GElf_Word type,
-			     GElf_Addr vaddr, GElf_Xword memsz,
-			     GElf_Off offset, GElf_Xword filesz,
-			     GElf_Xword align)
+  INLINE_NESTED_FUNC (void, consider_phdr,
+                      (GElf_Word,
+                       GElf_Addr, GElf_Xword,
+                       GElf_Off, GElf_Xword,
+                       GElf_Xword),
+                      (GElf_Word type,
+                       GElf_Addr vaddr, GElf_Xword memsz,
+                       GElf_Off offset, GElf_Xword filesz,
+                       GElf_Xword align))
   {
     switch (type)
       {
@@ -571,7 +590,7 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 	  module_end = vaddr_end;
 	break;
       }
-  }
+  };
 
   Elf32_Phdr (*p32)[phnum] = phdrsp;
   Elf64_Phdr (*p64)[phnum] = phdrsp;
@@ -718,11 +737,12 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
      We need its DT_STRTAB and DT_STRSZ to decipher DT_SONAME,
      and they also tell us the essential portion of the file
      for fetching symbols.  */
-  GElf_Addr soname_stroff = 0;
-  GElf_Addr dynstr_vaddr = 0;
-  GElf_Xword dynstrsz = 0;
-  bool execlike = false;
-  inline bool consider_dyn (GElf_Sxword tag, GElf_Xword val)
+  __BLOCK GElf_Addr soname_stroff = 0;
+  __BLOCK GElf_Addr dynstr_vaddr = 0;
+  __BLOCK GElf_Xword dynstrsz = 0;
+  __BLOCK bool execlike = false;
+  INLINE_NESTED_FUNC (bool, consider_dyn, (GElf_Sxword, GElf_Xword),
+                      (GElf_Sxword tag, GElf_Xword val))
   {
     switch (tag)
       {
@@ -747,12 +767,12 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
       }
 
     return soname_stroff != 0 && dynstr_vaddr != 0 && dynstrsz != 0;
-  }
+  };
 
   const size_t dyn_entsize = (ei_class == ELFCLASS32
 			      ? sizeof (Elf32_Dyn) : sizeof (Elf64_Dyn));
-  void *dyn_data = NULL;
-  size_t dyn_data_size = 0;
+  __BLOCK void *dyn_data = NULL;
+  __BLOCK size_t dyn_data_size = 0;
   if (dyn_filesz != 0 && dyn_filesz % dyn_entsize == 0
       && ! read_portion (&dyn_data, &dyn_data_size, dyn_vaddr, dyn_filesz))
     {
@@ -790,8 +810,8 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
   if (name == NULL)
     name = e_type == ET_EXEC ? "[exe]" : execlike ? "[pie]" : "[dso]";
 
-  void *soname = NULL;
-  size_t soname_size = 0;
+  __BLOCK void *soname = NULL;
+  __BLOCK size_t soname_size = 0;
   if (! name_is_final && dynstrsz != 0 && dynstr_vaddr != 0)
     {
       /* We know the bounds of the .dynstr section.
@@ -824,7 +844,7 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
   /* Now that we have chosen the module's name and bounds, report it.
      If we found a build ID, report that too.  */
 
-  Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, name,
+  __BLOCK Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, name,
 						 module_start, module_end);
 
   // !execlike && ET_EXEC is PIE.
@@ -872,29 +892,34 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
       /* The caller wants to read the whole file in right now, but hasn't
 	 done it for us.  Fill in a local image of the virtual file.  */
 
-      void *contents = calloc (1, file_trimmed_end);
+      __BLOCK void *contents = calloc (1, file_trimmed_end);
       if (unlikely (contents == NULL))
 	return finish ();
 
-      inline void final_read (size_t offset, GElf_Addr vaddr, size_t size)
+      INLINE_NESTED_FUNC (void, final_read,
+                          (size_t, GElf_Addr, size_t),
+                          (size_t offset, GElf_Addr vaddr, size_t size))
       {
 	void *into = contents + offset;
 	size_t read_size = size;
 	(void) segment_read (addr_segndx (dwfl, segment, vaddr, false),
 			     &into, &read_size, vaddr, size);
-      }
+      };
 
       if (contiguous < file_trimmed_end)
 	{
 	  /* We can't use the memory image verbatim as the file image.
 	     So we'll be reading into a local image of the virtual file.  */
 
-	  inline void read_phdr (GElf_Word type, GElf_Addr vaddr,
-				 GElf_Off offset, GElf_Xword filesz)
+	  INLINE_NESTED_FUNC (void, read_phdr,
+	                      (GElf_Word, GElf_Addr,
+	                       GElf_Off, GElf_Xword),
+	                      (GElf_Word type, GElf_Addr vaddr,
+	                       GElf_Off offset, GElf_Xword filesz))
 	  {
 	    if (type == PT_LOAD)
 	      final_read (offset, vaddr + bias, filesz);
-	  }
+	  };
 
 	  if (ei_class == ELFCLASS32)
 	    for (uint_fast16_t i = 0; i < phnum; ++i)
diff --git a/libdwfl/elf-from-memory.c b/libdwfl/elf-from-memory.c
index 12a0a1b..e63b7b2 100644
--- a/libdwfl/elf-from-memory.c
+++ b/libdwfl/elf-from-memory.c
@@ -219,33 +219,37 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
   Elf64_Phdr (*p64)[phnum] = phdrsp;
   switch (ehdr.e32.e_ident[EI_CLASS])
     {
-      /* Sanity checks segments and calculates segment_end,
-	 segments_end, segments_end_mem and loadbase (if not
-	 found_base yet).  Returns true if sanity checking failed,
-	 false otherwise.  */
-      inline bool handle_segment (GElf_Addr vaddr, GElf_Off offset,
-				  GElf_Xword filesz, GElf_Xword memsz)
-	{
-	  /* Sanity check the segment load aligns with the pagesize.  */
-	  if (((vaddr - offset) & (pagesize - 1)) != 0)
-	    return true;
-
-	  GElf_Off segment_end = ((offset + filesz + pagesize - 1)
-				  & -pagesize);
-
-	  if (segment_end > (GElf_Off) contents_size)
-	    contents_size = segment_end;
-
-	  if (!found_base && (offset & -pagesize) == 0)
-	    {
-	      loadbase = ehdr_vma - (vaddr & -pagesize);
-	      found_base = true;
-	    }
-
-	  segments_end = offset + filesz;
-	  segments_end_mem = offset + memsz;
-	  return false;
-	}
+  /* Sanity checks segments and calculates segment_end,
+   segments_end, segments_end_mem and loadbase (if not
+   found_base yet).  Returns true if sanity checking failed,
+   false otherwise.  */
+  #define handle_segment(_vaddr, _offset, _filesz, _memsz) \
+    ( { \
+      bool result; \
+      GElf_Addr vaddr = _vaddr; \
+      GElf_Off offset = _offset; \
+      GElf_Xword filesz = _filesz; \
+      GElf_Xword memsz = _memsz; \
+      /* Sanity check the segment load aligns with the pagesize.  */ \
+      if (((vaddr - offset) & (pagesize - 1)) != 0) \
+        result = true; \
+      else \
+        { \
+          result = false; \
+          GElf_Off segment_end = ((offset + filesz + pagesize - 1) \
+                                 & -pagesize); \
+          if (segment_end > (GElf_Off) contents_size) \
+            contents_size = segment_end; \
+          if (!found_base && (offset & -pagesize) == 0) \
+            { \
+              loadbase = ehdr_vma - (vaddr & -pagesize); \
+              found_base = true; \
+            } \
+          segments_end = offset + filesz; \
+          segments_end_mem = offset + memsz; \
+        } \
+      result; \
+    } )
 
     case ELFCLASS32:
       if (elf32_xlatetom (&xlateto, &xlatefrom,
@@ -302,19 +306,22 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
   switch (ehdr.e32.e_ident[EI_CLASS])
     {
       /* Reads the given segment.  Returns true if reading fails,
-	 false otherwise.  */
-      inline bool handle_segment (GElf_Addr vaddr, GElf_Off offset,
-				  GElf_Xword filesz)
-	{
-	  GElf_Off start = offset & -pagesize;
-	  GElf_Off end = (offset + filesz + pagesize - 1) & -pagesize;
-	  if (end > (GElf_Off) contents_size)
-	    end = contents_size;
-	  nread = (*read_memory) (arg, buffer + start,
-				  (loadbase + vaddr) & -pagesize,
-				  end - start, end - start);
-	  return nread <= 0;
-	}
+         false otherwise.  */
+      #undef handle_segment
+      #define handle_segment(_vaddr, _offset, _filesz) \
+        ( { \
+          GElf_Addr vaddr = _vaddr; \
+          GElf_Off offset = _offset; \
+          GElf_Xword filesz = _filesz; \
+          GElf_Off start = offset & -pagesize; \
+          GElf_Off end = (offset + filesz + pagesize - 1) & -pagesize; \
+          if (end > (GElf_Off) contents_size) \
+            end = contents_size; \
+          nread = (*read_memory) (arg, buffer + start, \
+                                  (loadbase + vaddr) & -pagesize, \
+                                   end - start, end - start); \
+          (nread <= 0); \
+        } )
 
     case ELFCLASS32:
       for (uint_fast16_t i = 0; i < phnum; ++i)
diff --git a/libdwfl/link_map.c b/libdwfl/link_map.c
index 794668f..b462807 100644
--- a/libdwfl/link_map.c
+++ b/libdwfl/link_map.c
@@ -30,6 +30,7 @@
 #include "libdwflP.h"
 #include "../libdw/memory-access.h"
 #include "system.h"
+#include "nested_func.h"
 
 #include <byteswap.h>
 #include <endian.h>
@@ -249,20 +250,27 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata,
 		struct r_debug_info *r_debug_info)
 {
   /* Skip r_version, to aligned r_map field.  */
-  GElf_Addr read_vaddr = r_debug_vaddr + addrsize (elfclass);
+  __BLOCK GElf_Addr read_vaddr = r_debug_vaddr + addrsize (elfclass);
 
-  void *buffer = NULL;
-  size_t buffer_available = 0;
-  inline int release_buffer (int result)
+  __BLOCK void *buffer = NULL;
+  __BLOCK size_t buffer_available = 0;
+  INLINE_NESTED_FUNC (int, release_buffer, (int), (int result))
   {
     if (buffer != NULL)
       (void) (*memory_callback) (dwfl, -1, &buffer, &buffer_available, 0, 0,
 				 memory_callback_arg);
     return result;
-  }
-
-  GElf_Addr addrs[4];
-  inline bool read_addrs (GElf_Addr vaddr, size_t n)
+  };
+
+#if __clang__
+  /* Clang Blocks cannot copy an array to a closure. */
+  __BLOCK GElf_Addr *addrs = alloca(4 * sizeof (GElf_Addr));
+#else
+  /* gcc complains about unbounded stack usage from alloca. */
+   GElf_Addr addrs[4];
+#endif
+  INLINE_NESTED_FUNC (bool, read_addrs,
+                      (GElf_Addr, size_t), (GElf_Addr vaddr, size_t n))
   {
     size_t nb = n * addrsize (elfclass); /* Address words -> bytes to read.  */
 
@@ -305,7 +313,7 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata,
       }
 
     return false;
-  }
+  };
 
   if (unlikely (read_addrs (read_vaddr, 1)))
     return release_buffer (-1);
@@ -690,7 +698,6 @@ find_executable (Dwfl *dwfl, GElf_Addr at_phdr, GElf_Addr at_entry,
 
   return 0;
 }
-\f
 
 int
 dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
@@ -698,17 +705,17 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 		      void *memory_callback_arg,
 		      struct r_debug_info *r_debug_info)
 {
-  GElf_Addr r_debug_vaddr = 0;
+  __BLOCK GElf_Addr r_debug_vaddr = 0;
 
-  uint_fast8_t elfclass = ELFCLASSNONE;
-  uint_fast8_t elfdata = ELFDATANONE;
+  __BLOCK uint_fast8_t elfclass = ELFCLASSNONE;
+  __BLOCK uint_fast8_t elfdata = ELFDATANONE;
   if (likely (auxv != NULL)
       && likely (auxv_format_probe (auxv, auxv_size, &elfclass, &elfdata)))
     {
-      GElf_Addr entry = 0;
-      GElf_Addr phdr = 0;
-      GElf_Xword phent = 0;
-      GElf_Xword phnum = 0;
+      __BLOCK GElf_Addr entry = 0;
+      __BLOCK GElf_Addr phdr = 0;
+      __BLOCK GElf_Xword phent = 0;
+      __BLOCK GElf_Xword phnum = 0;
 
 #define READ_AUXV32(ptr)	read_4ubyte_unaligned_noncvt (ptr)
 #define READ_AUXV64(ptr)	read_8ubyte_unaligned_noncvt (ptr)
@@ -754,12 +761,13 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 	}
 
       /* If we found the phdr dimensions, search phdrs for PT_DYNAMIC.  */
-      GElf_Addr dyn_vaddr = 0;
-      GElf_Xword dyn_filesz = 0;
-      GElf_Addr dyn_bias = (GElf_Addr) -1;
+      __BLOCK GElf_Addr dyn_vaddr = 0;
+      __BLOCK GElf_Xword dyn_filesz = 0;
+      __BLOCK GElf_Addr dyn_bias = (GElf_Addr) -1;
 
-      inline bool consider_phdr (GElf_Word type,
-				 GElf_Addr vaddr, GElf_Xword filesz)
+      INLINE_NESTED_FUNC (bool, consider_phdr,
+                          (GElf_Word, GElf_Addr, GElf_Xword),
+                          (GElf_Word type, GElf_Addr vaddr, GElf_Xword filesz))
       {
 	switch (type)
 	  {
@@ -781,7 +789,7 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 	  }
 
 	return false;
-      }
+      };
 
       if (phdr != 0 && phnum != 0)
 	{
diff --git a/src/addr2line.c b/src/addr2line.c
index ba414a7..f939a87 100644
--- a/src/addr2line.c
+++ b/src/addr2line.c
@@ -692,19 +692,22 @@ handle_address (const char *string, Dwfl *dwfl)
 	  Dwarf_Line *info = dwfl_dwarf_line (line, &bias);
 	  assert (info != NULL);
 
-	  inline void show (int (*get) (Dwarf_Line *, bool *),
-			    const char *note)
-	  {
-	    bool flag;
-	    if ((*get) (info, &flag) == 0 && flag)
-	      fputs (note, stdout);
+	  #define show(get_arg, note_arg) \
+	  { \
+	    int (*get) (Dwarf_Line *, bool *) = get_arg; \
+	    const char *note = note_arg; \
+	    bool flag; \
+	    if ((*get) (info, &flag) == 0 && flag) \
+	      fputs (note, stdout); \
 	  }
-	  inline void show_int (int (*get) (Dwarf_Line *, unsigned int *),
-				const char *name)
-	  {
-	    unsigned int val;
-	    if ((*get) (info, &val) == 0 && val != 0)
-	      printf (" (%s %u)", name, val);
+
+	  #define show_int(get_arg, name_arg) \
+	  { \
+	    int (*get) (Dwarf_Line *, unsigned int *) = get_arg; \
+	    const char *name = name_arg; \
+	    unsigned int val; \
+	    if ((*get) (info, &val) == 0 && val != 0) \
+	      printf (" (%s %u)", name, val); \
 	  }
 
 	  show (&dwarf_linebeginstatement, " (is_stmt)");
diff --git a/src/ar.c b/src/ar.c
index ec32cee..7ba2b11 100644
--- a/src/ar.c
+++ b/src/ar.c
@@ -446,20 +446,21 @@ do_oper_extract (int oper, const char *arfname, char **argv, int argc,
   memset (found, '\0', sizeof (found));
 
   size_t name_max = 0;
-  inline bool should_truncate_fname (void)
-  {
-    if (errno == ENAMETOOLONG && allow_truncate_fname)
-      {
-	if (name_max == 0)
-	  {
-	    long int len = pathconf (".", _PC_NAME_MAX);
-	    if (len > 0)
-	      name_max = len;
-	  }
-	return name_max != 0;
-      }
-    return false;
-  }
+  #define should_truncate_fname() \
+  ( { \
+    bool result = false; \
+    if (errno == ENAMETOOLONG && allow_truncate_fname) \
+      { \
+	if (name_max == 0) \
+	  { \
+	    long int len = pathconf (".", _PC_NAME_MAX); \
+	    if (len > 0) \
+	      name_max = len; \
+	  } \
+	result = (name_max != 0); \
+      } \
+    result; \
+  } )
 
   off_t index_off = -1;
   size_t index_size = 0;
diff --git a/src/arlib-argp.c b/src/arlib-argp.c
index 1bdd8d0..3b52479 100644
--- a/src/arlib-argp.c
+++ b/src/arlib-argp.c
@@ -59,13 +59,13 @@ parse_opt (int key, char *arg __attribute__ ((unused)),
 static char *
 help_filter (int key, const char *text, void *input __attribute__ ((unused)))
 {
-  inline char *text_for_default (void)
-  {
-    char *new_text;
-    if (unlikely (asprintf (&new_text, gettext ("%s (default)"), text) < 0))
-      return (char *) text;
-    return new_text;
-  }
+  #define text_for_default() \
+  ( { \
+    char *new_text; \
+    if (unlikely (asprintf (&new_text, gettext ("%s (default)"), text) < 0)) \
+      new_text = (char *) text; \
+    new_text; \
+  } )
 
   switch (key)
     {
diff --git a/src/elfcompress.c b/src/elfcompress.c
index 8e0d5c5..893c6b4 100644
--- a/src/elfcompress.c
+++ b/src/elfcompress.c
@@ -276,50 +276,43 @@ process_file (const char *fname)
   size_t shnum = 0;
 
 #define WORD_BITS (8U * sizeof (unsigned int))
-  void set_section (size_t ndx)
-  {
-    sections[ndx / WORD_BITS] |= (1U << (ndx % WORD_BITS));
-  }
 
-  bool get_section (size_t ndx)
-  {
-    return (sections[ndx / WORD_BITS] & (1U << (ndx % WORD_BITS))) != 0;
-  }
-
-  int cleanup (int res)
-  {
-    elf_end (elf);
-    close (fd);
-
-    elf_end (elfnew);
-    close (fdnew);
-
-    if (fnew != NULL)
-      {
-	unlink (fnew);
-	free (fnew);
-	fnew = NULL;
-      }
-
-    free (snamebuf);
-    if (names != NULL)
-      {
-	dwelf_strtab_free (names);
-	free (scnstrents);
-	free (symstrents);
-	free (namesbuf);
-	if (scnnames != NULL)
-	  {
-	    for (size_t n = 0; n < shnum; n++)
-	      free (scnnames[n]);
-	    free (scnnames);
-	  }
-      }
-
-    free (sections);
-
-    return res;
-  }
+#define set_section(ndx) \
+  sections[ndx / WORD_BITS] |= (1U << (ndx % WORD_BITS))
+
+#define get_section(ndx) \
+  ((sections[ndx / WORD_BITS] & (1U << (ndx % WORD_BITS))) != 0)
+
+  #define cleanup(res) \
+    ( { \
+        int result = res; \
+        elf_end (elf); \
+        close (fd); \
+        elf_end (elfnew); \
+        close (fdnew); \
+        if (fnew != NULL) \
+          { \
+	    unlink (fnew); \
+	    free (fnew); \
+	    fnew = NULL; \
+          } \
+        free (snamebuf); \
+        if (names != NULL) \
+          { \
+	    dwelf_strtab_free (names); \
+	    free (scnstrents); \
+	    free (symstrents); \
+	    free (namesbuf); \
+	    if (scnnames != NULL) \
+	      { \
+	        for (size_t n = 0; n < shnum; n++) \
+	          free (scnnames[n]); \
+	        free (scnnames); \
+	      } \
+          } \
+        free (sections); \
+      result; \
+    } )
 
   fd = open (fname, O_RDONLY);
   if (fd < 0)
diff --git a/src/elflint.c b/src/elflint.c
index 51e53c2..2463f92 100644
--- a/src/elflint.c
+++ b/src/elflint.c
@@ -3433,10 +3433,8 @@ check_attributes (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
       return;
     }
 
-  inline size_t pos (const unsigned char *p)
-  {
-    return p - (const unsigned char *) data->d_buf;
-  }
+  #define pos(p) \
+    ((const unsigned char *) (p) - (const unsigned char *) data->d_buf)
 
   const unsigned char *p = data->d_buf;
   if (*p++ != 'A')
@@ -3446,10 +3444,7 @@ check_attributes (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
       return;
     }
 
-  inline size_t left (void)
-  {
-    return (const unsigned char *) data->d_buf + data->d_size - p;
-  }
+  #define left() ((const unsigned char *) data->d_buf + data->d_size - p)
 
   while (left () >= 4)
     {
diff --git a/src/readelf.c b/src/readelf.c
index 5e2f3fc..a32a22b 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -333,16 +333,18 @@ static error_t
 parse_opt (int key, char *arg,
 	   struct argp_state *state __attribute__ ((unused)))
 {
-  void add_dump_section (const char *name, bool implicit)
-  {
-    struct section_argument *a = xmalloc (sizeof *a);
-    a->arg = name;
-    a->next = NULL;
-    a->implicit = implicit;
-    struct section_argument ***tailp
-      = key == 'x' ? &dump_data_sections_tail : &string_sections_tail;
-    **tailp = a;
-    *tailp = &a->next;
+  #define add_dump_section(name_arg, implicit_arg) \
+  { \
+    const char *name = name_arg; \
+    bool implicit = implicit_arg; \
+    struct section_argument *a = xmalloc (sizeof *a); \
+    a->arg = name; \
+    a->next = NULL; \
+    a->implicit = implicit; \
+    struct section_argument ***tailp \
+      = key == 'x' ? &dump_data_sections_tail : &string_sections_tail; \
+    **tailp = a; \
+    *tailp = &a->next; \
   }
 
   switch (key)
@@ -3470,10 +3472,7 @@ print_attributes (Ebl *ebl, const GElf_Ehdr *ehdr)
 
       fputs_unlocked (gettext ("  Owner          Size\n"), stdout);
 
-      inline size_t left (void)
-      {
-	return (const unsigned char *) data->d_buf + data->d_size - p;
-      }
+      #define left() ((const unsigned char *) data->d_buf + data->d_size - p)
 
       /* Loop over the sections.  */
       while (left () >= 4)
@@ -5166,11 +5165,12 @@ print_cfa_program (const unsigned char *readp, const unsigned char *const endp,
 		   Dwfl_Module *dwflmod, Ebl *ebl, Dwarf *dbg)
 {
   char regnamebuf[REGNAMESZ];
-  const char *regname (unsigned int regno)
-  {
-    register_info (ebl, regno, NULL, regnamebuf, NULL, NULL);
-    return regnamebuf;
-  }
+  #define regname(regno_arg) \
+  ( { \
+    unsigned int regno = regno_arg; \
+    register_info (ebl, regno, NULL, regnamebuf, NULL, NULL); \
+    regnamebuf; \
+  } )
 
   puts ("\n   Program:");
   Dwarf_Word pc = vma_base;
@@ -6742,14 +6742,16 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
 	 or DW_LNS_advance_pc (as per DWARF4 6.2.5.1).  */
       unsigned int op_addr_advance;
       bool show_op_index;
-      inline void advance_pc (unsigned int op_advance)
-      {
-	op_addr_advance = minimum_instr_len * ((op_index + op_advance)
-					       / max_ops_per_instr);
-	address += op_advance;
-	show_op_index = (op_index > 0 ||
-			 (op_index + op_advance) % max_ops_per_instr > 0);
-	op_index = (op_index + op_advance) % max_ops_per_instr;
+
+      #define advance_pc(op_advance_arg) \
+      { \
+        unsigned int op_advance = op_advance_arg; \
+	op_addr_advance = minimum_instr_len * ((op_index + (op_advance)) \
+					       / max_ops_per_instr); \
+	address += (op_advance); \
+	show_op_index = (op_index > 0 || \
+			 (op_index + (op_advance)) % max_ops_per_instr > 0); \
+	op_index = (op_index + (op_advance)) % max_ops_per_instr; \
       }
 
       if (max_ops_per_instr == 0)
@@ -9160,14 +9162,16 @@ handle_core_registers (Ebl *ebl, Elf *core, const void *desc,
   qsort (regs, maxreg + 1, sizeof regs[0], &compare_registers);
 
   /* Collect the unique sets and sort them.  */
-  inline bool same_set (const struct register_info *a,
-			const struct register_info *b)
-  {
-    return (a < &regs[maxnreg] && a->regloc != NULL
-	    && b < &regs[maxnreg] && b->regloc != NULL
-	    && a->bits == b->bits
-	    && (a->set == b->set || !strcmp (a->set, b->set)));
-  }
+  #define same_set(a_arg, b_arg) \
+  ( { \
+    const struct register_info *a = a_arg; \
+    const struct register_info *b = b_arg; \
+    (a < &regs[maxnreg] && a->regloc != NULL \
+	    && b < &regs[maxnreg] && b->regloc != NULL \
+	    && a->bits == b->bits \
+	    && (a->set == b->set || !strcmp (a->set, b->set))); \
+  } )
+
   struct register_info *sets[maxreg + 1];
   sets[0] = &regs[0];
   size_t nsets = 1;
diff --git a/src/strip.c b/src/strip.c
index 773ed54..d0a0d01 100644
--- a/src/strip.c
+++ b/src/strip.c
@@ -457,6 +457,167 @@ process_file (const char *fname)
 /* Maximum size of array allocated on stack.  */
 #define MAX_STACK_ALLOC	(400 * 1024)
 
+struct shdr_info
+{
+  Elf_Scn *scn;
+  GElf_Shdr shdr;
+  Elf_Data *data;
+  Elf_Data *debug_data;
+  const char *name;
+  Elf32_Word idx;		/* Index in new file.  */
+  Elf32_Word old_sh_link;	/* Original value of shdr.sh_link.  */
+  Elf32_Word symtab_idx;
+  Elf32_Word version_idx;
+  Elf32_Word group_idx;
+  Elf32_Word group_cnt;
+  Elf_Scn *newscn;
+  Dwelf_Strent *se;
+  Elf32_Word *newsymidx;
+};
+
+#define declare_relocate_closure \
+  Ebl * const ebl, \
+  Elf_Data * const symdata, \
+  Elf_Data * const xndxdata, \
+  size_t const shnum, \
+  const char * const fname, \
+  struct shdr_info * const shdr_info, \
+  Elf_Data * const tdata, \
+  Elf * const debugelf, \
+  GElf_Ehdr * const ehdr
+
+#define pass_relocate_closure \
+  ebl, symdata, xndxdata, shnum, fname, shdr_info, tdata, debugelf, ehdr
+
+/* Apply one relocation.  Returns true when trivial
+  relocation actually done.  */
+static bool
+relocate (declare_relocate_closure, GElf_Addr offset,
+          const GElf_Sxword addend, bool is_rela, int rtype, int symndx)
+{
+		/* R_*_NONE relocs can always just be removed.  */
+		if (rtype == 0)
+		  return true;
+
+		/* We only do simple absolute relocations.  */
+		Elf_Type type = ebl_reloc_simple_type (ebl, rtype);
+		if (type == ELF_T_NUM)
+		  return false;
+
+		/* These are the types we can relocate.  */
+#define TYPES   DO_TYPE (BYTE, Byte); DO_TYPE (HALF, Half);		\
+		DO_TYPE (WORD, Word); DO_TYPE (SWORD, Sword);		\
+		DO_TYPE (XWORD, Xword); DO_TYPE (SXWORD, Sxword)
+
+		/* And only for relocations against other debug sections.  */
+		GElf_Sym sym_mem;
+		Elf32_Word xndx;
+		GElf_Sym *sym = gelf_getsymshndx (symdata, xndxdata,
+						  symndx, &sym_mem,
+						  &xndx);
+		Elf32_Word sec = (sym->st_shndx == SHN_XINDEX
+				  ? xndx : sym->st_shndx);
+		if (sec >= shnum + 2)
+		  INTERNAL_ERROR (fname);
+
+		if (ebl_debugscn_p (ebl, shdr_info[sec].name))
+		  {
+		    size_t size;
+
+#define DO_TYPE(NAME, Name) GElf_##Name Name;
+		    union { TYPES; } tmpbuf;
+#undef DO_TYPE
+
+		    switch (type)
+		      {
+#define DO_TYPE(NAME, Name)				\
+			case ELF_T_##NAME:		\
+			  size = sizeof (GElf_##Name);	\
+			  tmpbuf.Name = 0;		\
+			  break;
+			TYPES;
+#undef DO_TYPE
+		      default:
+			return false;
+		      }
+
+		    if (offset > tdata->d_size
+			|| tdata->d_size - offset < size)
+		      {
+			cleanup_debug ();
+			error (EXIT_FAILURE, 0, gettext ("bad relocation"));
+		      }
+
+		    /* When the symbol value is zero then for SHT_REL
+		       sections this is all that needs to be checked.
+		       The addend is contained in the original data at
+		       the offset already.  So if the (section) symbol
+		       address is zero and the given addend is zero
+		       just remove the relocation, it isn't needed
+		       anymore.  */
+		    if (addend == 0 && sym->st_value == 0)
+		      return true;
+
+		    Elf_Data tmpdata =
+		      {
+			.d_type = type,
+			.d_buf = &tmpbuf,
+			.d_size = size,
+			.d_version = EV_CURRENT,
+		      };
+		    Elf_Data rdata =
+		      {
+			.d_type = type,
+			.d_buf = tdata->d_buf + offset,
+			.d_size = size,
+			.d_version = EV_CURRENT,
+		      };
+
+		    GElf_Addr value = sym->st_value;
+		    if (is_rela)
+		      {
+			/* For SHT_RELA sections we just take the
+			   given addend and add it to the value.  */
+			value += addend;
+		      }
+		    else
+		      {
+			/* For SHT_REL sections we have to peek at
+			   what is already in the section at the given
+			   offset to get the addend.  */
+			Elf_Data *d = gelf_xlatetom (debugelf, &tmpdata,
+						     &rdata,
+						     ehdr->e_ident[EI_DATA]);
+			if (d == NULL)
+			  INTERNAL_ERROR (fname);
+			assert (d == &tmpdata);
+		      }
+
+		    switch (type)
+		      {
+#define DO_TYPE(NAME, Name)					\
+			case ELF_T_##NAME:			\
+			  tmpbuf.Name += (GElf_##Name) value;	\
+			  break;
+			TYPES;
+#undef DO_TYPE
+		      default:
+			abort ();
+		      }
+
+		    /* Now finally put in the new value.  */
+		    Elf_Data *s = gelf_xlatetof (debugelf, &rdata,
+						 &tmpdata,
+						 ehdr->e_ident[EI_DATA]);
+		    if (s == NULL)
+		      INTERNAL_ERROR (fname);
+		    assert (s == &rdata);
+
+		    return true;
+		  }
+		return false;
+}
+
 static int
 handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
 	    mode_t mode, struct timespec tvp[2])
@@ -470,23 +631,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
   int result = 0;
   size_t shdridx = 0;
   size_t shstrndx;
-  struct shdr_info
-  {
-    Elf_Scn *scn;
-    GElf_Shdr shdr;
-    Elf_Data *data;
-    Elf_Data *debug_data;
-    const char *name;
-    Elf32_Word idx;		/* Index in new file.  */
-    Elf32_Word old_sh_link;	/* Original value of shdr.sh_link.  */
-    Elf32_Word symtab_idx;
-    Elf32_Word version_idx;
-    Elf32_Word group_idx;
-    Elf32_Word group_cnt;
-    Elf_Scn *newscn;
-    Dwelf_Strent *se;
-    Elf32_Word *newsymidx;
-  } *shdr_info = NULL;
+  struct shdr_info *shdr_info = NULL;
   Elf_Scn *scn;
   size_t cnt;
   size_t idx;
@@ -1024,19 +1169,19 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
 		 file's .data pointer.  Below, we'll copy the section
 		 contents.  */
 
-	      inline void check_preserved (size_t i)
-	      {
-		if (i != 0 && i < shnum + 2 && shdr_info[i].idx != 0
-		    && shdr_info[i].debug_data == NULL)
-		  {
-		    if (shdr_info[i].data == NULL)
-		      shdr_info[i].data = elf_getdata (shdr_info[i].scn, NULL);
-		    if (shdr_info[i].data == NULL)
-		      INTERNAL_ERROR (fname);
-
-		    shdr_info[i].debug_data = shdr_info[i].data;
-		    changes |= i < cnt;
-		  }
+	      #define check_preserved(i_arg) \
+	      { \
+		size_t i = i_arg; \
+		if (i != 0 && i < shnum + 2 && shdr_info[i].idx != 0 \
+		    && shdr_info[i].debug_data == NULL) \
+		  { \
+		    if (shdr_info[i].data == NULL) \
+		      shdr_info[i].data = elf_getdata (shdr_info[i].scn, NULL); \
+		    if (shdr_info[i].data == NULL) \
+		      INTERNAL_ERROR (fname); \
+		    shdr_info[i].debug_data = shdr_info[i].data; \
+		    changes |= i < cnt; \
+		  } \
 	      }
 
 	      check_preserved (shdr_info[cnt].shdr.sh_link);
@@ -1562,21 +1707,22 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
 	/* Update section headers when the data size has changed.
 	   We also update the SHT_NOBITS section in the debug
 	   file so that the section headers match in sh_size.  */
-	inline void update_section_size (const Elf_Data *newdata)
-	{
-	  GElf_Shdr shdr_mem;
-	  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
-	  shdr->sh_size = newdata->d_size;
-	  (void) gelf_update_shdr (scn, shdr);
-	  if (debugelf != NULL)
-	    {
-	      /* libelf will use d_size to set sh_size.  */
-	      Elf_Data *debugdata = elf_getdata (elf_getscn (debugelf,
-							     cnt), NULL);
-	      if (debugdata == NULL)
-		INTERNAL_ERROR (fname);
-	      debugdata->d_size = newdata->d_size;
-	    }
+	#define update_section_size(newdata_arg) \
+	{ \
+	  const Elf_Data *newdata = newdata_arg; \
+	  GElf_Shdr shdr_mem; \
+	  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); \
+	  shdr->sh_size = newdata->d_size; \
+	  (void) gelf_update_shdr (scn, shdr); \
+	  if (debugelf != NULL) \
+	    { \
+	      /* libelf will use d_size to set sh_size.  */ \
+	      Elf_Data *debugdata = elf_getdata (elf_getscn (debugelf, \
+							     cnt), NULL); \
+	      if (debugdata == NULL) \
+		INTERNAL_ERROR (fname); \
+	      debugdata->d_size = newdata->d_size; \
+	    } \
 	}
 
 	if (shdr_info[cnt].idx == 0 && debug_fname == NULL)
@@ -1590,18 +1736,21 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
 	const Elf32_Word *const newsymidx = shdr_info[symtabidx].newsymidx;
 	switch (shdr_info[cnt].shdr.sh_type)
 	  {
-	    inline bool no_symtab_updates (void)
-	    {
-	      /* If the symbol table hasn't changed, do not do anything.  */
-	      if (shdr_info[symtabidx].newsymidx == NULL)
-		return true;
-
-	      /* If the symbol table is not discarded, but additionally
-		 duplicated in the separate debug file and this section
-		 is discarded, don't adjust anything.  */
-	      return (shdr_info[cnt].idx == 0
-		      && shdr_info[symtabidx].debug_data != NULL);
-	    }
+	    #define no_symtab_updates() \
+	    ( { \
+	        bool no_updates; \
+	        /* If the symbol table hasn't changed, do not do anything.  */ \
+	        if (shdr_info[symtabidx].newsymidx == NULL) { \
+	          no_updates = true; \
+	        } else { \
+	          /* If the symbol table is not discarded, but additionally */ \
+	          /* duplicated in the separate debug file and this section */ \
+	          /* is discarded, don't adjust anything. */ \
+	          no_updates = (shdr_info[cnt].idx == 0 \
+	                        && shdr_info[symtabidx].debug_data != NULL); \
+	        } \
+	        no_updates; \
+	    } )
 
 	  case SHT_REL:
 	  case SHT_RELA:
@@ -1936,134 +2085,6 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
 	      xndxdata = (shdr_info[shdr_info[symt].symtab_idx].debug_data
 			  ?: shdr_info[shdr_info[symt].symtab_idx].data);
 
-	      /* Apply one relocation.  Returns true when trivial
-		 relocation actually done.  */
-	      bool relocate (GElf_Addr offset, const GElf_Sxword addend,
-			     bool is_rela, int rtype, int symndx)
-	      {
-		/* R_*_NONE relocs can always just be removed.  */
-		if (rtype == 0)
-		  return true;
-
-		/* We only do simple absolute relocations.  */
-		Elf_Type type = ebl_reloc_simple_type (ebl, rtype);
-		if (type == ELF_T_NUM)
-		  return false;
-
-		/* These are the types we can relocate.  */
-#define TYPES   DO_TYPE (BYTE, Byte); DO_TYPE (HALF, Half);		\
-		DO_TYPE (WORD, Word); DO_TYPE (SWORD, Sword);		\
-		DO_TYPE (XWORD, Xword); DO_TYPE (SXWORD, Sxword)
-
-		/* And only for relocations against other debug sections.  */
-		GElf_Sym sym_mem;
-		Elf32_Word xndx;
-		GElf_Sym *sym = gelf_getsymshndx (symdata, xndxdata,
-						  symndx, &sym_mem,
-						  &xndx);
-		Elf32_Word sec = (sym->st_shndx == SHN_XINDEX
-				  ? xndx : sym->st_shndx);
-		if (sec >= shnum + 2)
-		  INTERNAL_ERROR (fname);
-
-		if (ebl_debugscn_p (ebl, shdr_info[sec].name))
-		  {
-		    size_t size;
-
-#define DO_TYPE(NAME, Name) GElf_##Name Name;
-		    union { TYPES; } tmpbuf;
-#undef DO_TYPE
-
-		    switch (type)
-		      {
-#define DO_TYPE(NAME, Name)				\
-			case ELF_T_##NAME:		\
-			  size = sizeof (GElf_##Name);	\
-			  tmpbuf.Name = 0;		\
-			  break;
-			TYPES;
-#undef DO_TYPE
-		      default:
-			return false;
-		      }
-
-		    if (offset > tdata->d_size
-			|| tdata->d_size - offset < size)
-		      {
-			cleanup_debug ();
-			error (EXIT_FAILURE, 0, gettext ("bad relocation"));
-		      }
-
-		    /* When the symbol value is zero then for SHT_REL
-		       sections this is all that needs to be checked.
-		       The addend is contained in the original data at
-		       the offset already.  So if the (section) symbol
-		       address is zero and the given addend is zero
-		       just remove the relocation, it isn't needed
-		       anymore.  */
-		    if (addend == 0 && sym->st_value == 0)
-		      return true;
-
-		    Elf_Data tmpdata =
-		      {
-			.d_type = type,
-			.d_buf = &tmpbuf,
-			.d_size = size,
-			.d_version = EV_CURRENT,
-		      };
-		    Elf_Data rdata =
-		      {
-			.d_type = type,
-			.d_buf = tdata->d_buf + offset,
-			.d_size = size,
-			.d_version = EV_CURRENT,
-		      };
-
-		    GElf_Addr value = sym->st_value;
-		    if (is_rela)
-		      {
-			/* For SHT_RELA sections we just take the
-			   given addend and add it to the value.  */
-			value += addend;
-		      }
-		    else
-		      {
-			/* For SHT_REL sections we have to peek at
-			   what is already in the section at the given
-			   offset to get the addend.  */
-			Elf_Data *d = gelf_xlatetom (debugelf, &tmpdata,
-						     &rdata,
-						     ehdr->e_ident[EI_DATA]);
-			if (d == NULL)
-			  INTERNAL_ERROR (fname);
-			assert (d == &tmpdata);
-		      }
-
-		    switch (type)
-		      {
-#define DO_TYPE(NAME, Name)					\
-			case ELF_T_##NAME:			\
-			  tmpbuf.Name += (GElf_##Name) value;	\
-			  break;
-			TYPES;
-#undef DO_TYPE
-		      default:
-			abort ();
-		      }
-
-		    /* Now finally put in the new value.  */
-		    Elf_Data *s = gelf_xlatetof (debugelf, &rdata,
-						 &tmpdata,
-						 ehdr->e_ident[EI_DATA]);
-		    if (s == NULL)
-		      INTERNAL_ERROR (fname);
-		    assert (s == &rdata);
-
-		    return true;
-		  }
-		return false;
-	      }
-
 	      if (shdr->sh_entsize == 0)
 		INTERNAL_ERROR (fname);
 
@@ -2074,7 +2095,8 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
 		  {
 		    GElf_Rel rel_mem;
 		    GElf_Rel *r = gelf_getrel (reldata, relidx, &rel_mem);
-		    if (! relocate (r->r_offset, 0, false,
+		    if (! relocate (pass_relocate_closure,
+				    r->r_offset, 0, false,
 				    GELF_R_TYPE (r->r_info),
 				    GELF_R_SYM (r->r_info)))
 		      {
@@ -2088,7 +2110,8 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
 		  {
 		    GElf_Rela rela_mem;
 		    GElf_Rela *r = gelf_getrela (reldata, relidx, &rela_mem);
-		    if (! relocate (r->r_offset, r->r_addend, true,
+		    if (! relocate (pass_relocate_closure,
+				    r->r_offset, r->r_addend, true,
 				    GELF_R_TYPE (r->r_info),
 				    GELF_R_SYM (r->r_info)))
 		      {
diff --git a/src/unstrip.c b/src/unstrip.c
index 5074909..8f5da71 100644
--- a/src/unstrip.c
+++ b/src/unstrip.c
@@ -417,11 +417,12 @@ adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr,
 {
   Elf_Data *data = elf_getdata (outscn, NULL);
 
-  inline void adjust_reloc (GElf_Xword *info)
-    {
-      size_t ndx = GELF_R_SYM (*info);
-      if (ndx != STN_UNDEF)
-	*info = GELF_R_INFO (map[ndx - 1], GELF_R_TYPE (*info));
+  #define adjust_reloc(info_arg) \
+    { \
+      GElf_Xword *info = info_arg; \
+      size_t ndx = GELF_R_SYM (*info); \
+      if (ndx != STN_UNDEF) \
+        *info = GELF_R_INFO (map[ndx - 1], GELF_R_TYPE (*info)); \
     }
 
   switch (shdr->sh_type)
@@ -1091,14 +1092,17 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
     }
 
   bool fail = false;
-  inline void check_match (bool match, Elf_Scn *scn, const char *name)
-    {
-      if (!match)
-	{
-	  fail = true;
-	  error (0, 0, _("cannot find matching section for [%zu] '%s'"),
-		 elf_ndxscn (scn), name);
-	}
+  #define check_match(match_arg, scn_arg, name_arg) \
+    { \
+      bool match = match_arg; \
+      Elf_Scn *scnp = scn_arg; \
+      const char *sect_name = name_arg; \
+      if (!match) \
+      { \
+        fail = true; \
+        error (0, 0, _("cannot find matching section for [%zu] '%s'"), \
+               elf_ndxscn (scnp), sect_name); \
+      } \
     }
 
   Elf_Scn *scn = NULL;
@@ -1324,25 +1328,29 @@ more sections in stripped file than debug file -- arguments reversed?"));
     }
 
   /* Locate a matching unallocated section in SECTIONS.  */
-  inline struct section *find_unalloc_section (const GElf_Shdr *shdr,
-					       const char *name)
-    {
-      size_t l = nalloc, u = stripped_shnum - 1;
-      while (l < u)
-	{
-	  size_t i = (l + u) / 2;
-	  struct section *sec = &sections[i];
-	  int cmp = compare_unalloc_sections (shdr, &sec->shdr,
-					      name, sec->name);
-	  if (cmp < 0)
-	    u = i;
-	  else if (cmp > 0)
-	    l = i + 1;
-	  else
-	    return sec;
-	}
-      return NULL;
-    }
+  #define find_unalloc_section(shdr_arg, name_arg) \
+    ( { \
+        const GElf_Shdr *shdr_p = shdr_arg; \
+        const char *sect_name = name_arg; \
+        struct section * result = NULL; \
+        size_t l = nalloc, u = stripped_shnum - 1; \
+        while (l < u) \
+        { \
+          size_t i = (l + u) / 2; \
+          struct section *secp = &sections[i]; \
+          int cmp = compare_unalloc_sections (shdr_p, &secp->shdr, \
+                                              sect_name, secp->name); \
+          if (cmp < 0) \
+            u = i; \
+          else if (cmp > 0) \
+            l = i + 1; \
+          else { \
+            result = secp; \
+            break; \
+          } \
+        } \
+      result; \
+    } )
 
   Elf_Data *shstrtab = elf_getdata (elf_getscn (unstripped,
 						unstripped_shstrndx), NULL);
@@ -2061,13 +2069,14 @@ handle_explicit_files (const char *output_file, bool create_dirs, bool force,
 
   /* Warn, and exit if not forced to continue, if some ELF header
      sanity check for the stripped and unstripped files failed.  */
-  void warn (const char *msg)
-  {
-    error (force ? 0 : EXIT_FAILURE, 0, "%s'%s' and '%s' %s%s.",
-	   force ? _("WARNING: ") : "",
-	   stripped_file, unstripped_file, msg,
-	   force ? "" : _(", use --force"));
-  }
+  #define warn(msg_arg) \
+  { \
+    const char *msg = msg_arg; \
+    error (force ? 0 : EXIT_FAILURE, 0, "%s'%s' and '%s' %s%s.", \
+	   force ? _("WARNING: ") : "", \
+	   stripped_file, unstripped_file, msg, \
+	   force ? "" : _(", use --force")); \
+   }
 
   int stripped_fd = open_file (stripped_file, false);
   Elf *stripped = elf_begin (stripped_fd, ELF_C_READ, NULL);
@@ -2322,10 +2331,11 @@ static void
 handle_implicit_modules (const struct arg_info *info)
 {
   struct match_module_info mmi = { info->args, NULL, info->match_files };
-  inline ptrdiff_t next (ptrdiff_t offset)
-    {
-      return dwfl_getmodules (info->dwfl, &match_module, &mmi, offset);
-    }
+  #define next(offset_arg) \
+    ( { \
+      ptrdiff_t old_offset = offset_arg; \
+      dwfl_getmodules (info->dwfl, &match_module, &mmi, old_offset); \
+    } )
   ptrdiff_t offset = next (0);
   if (offset == 0)
     error (EXIT_FAILURE, 0, _("no matching modules found"));

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Compile elfutils with Clang
  2017-09-12 13:09   ` Dmitry Golovin
@ 2017-09-12 14:32     ` Ulf Hermann
  2017-09-12 15:25       ` Dmitry Golovin
  0 siblings, 1 reply; 5+ messages in thread
From: Ulf Hermann @ 2017-09-12 14:32 UTC (permalink / raw)
  To: elfutils-devel, dima

Hi Dmitry,

I would love to know how you implemented INLINE_NESTED_FUNC, but nested_func.h seems to be missing from your patch. Can you please double check this?

regards,
Ulf

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Compile elfutils with Clang
  2017-09-12 14:32     ` Ulf Hermann
@ 2017-09-12 15:25       ` Dmitry Golovin
  0 siblings, 0 replies; 5+ messages in thread
From: Dmitry Golovin @ 2017-09-12 15:25 UTC (permalink / raw)
  To: Ulf Hermann, elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 339 bytes --]

Hi Ulf,

Forgot to include it. I believe this file was also written by Chih-hung.

Regards,
Dmitry

12.09.2017, 17:32, "Ulf Hermann" <ulf.hermann@qt.io>:
> Hi Dmitry,
>
> I would love to know how you implemented INLINE_NESTED_FUNC, but nested_func.h seems to be missing from your patch. Can you please double check this?
>
> regards,
> Ulf

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: nested_func.h --]
[-- Type: text/x-c; name="nested_func.h", Size: 2769 bytes --]

/* Copyright (C) 2015 Red Hat, Inc.
   This file is part of elfutils.
   Written by Chih-Hung Hsieh <chh(a)google.com>, 2015.

   This file is free software; you can redistribute it and/or modify
   it under the terms of either

     * the GNU Lesser General Public License as published by the Free
       Software Foundation; either version 3 of the License, or (at
       your option) any later version

   or

     * the GNU General Public License as published by the Free
       Software Foundation; either version 2 of the License, or (at
       your option) any later version

   or both in parallel, as here.

   elfutils 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
   General Public License for more details.

   You should have received copies of the GNU General Public License and
   the GNU Lesser General Public License along with this program.  If
   not, see <http://www.gnu.org/licenses/>.  */

#ifndef _NESTED_FUNC_H
#define _NESTED_FUNC_H 1

#if __clang__

  #define __BLOCK __block

  #define NESTED_FUNC(return_type, function_name, \
                      arg_types, arg_types_and_names) \
    return_type (^function_name) arg_types = \
        ^ return_type arg_types_and_names

  /* Clang does not like inline keyword before a block variable. */
  #define INLINE_NESTED_FUNC(r, f, t, a) \
    NESTED_FUNC (r, f, t, a)

  #define INLINE_INTUSE_NESTED_FUNC(r, f, t, a) \
    NESTED_FUNC (r, INTUSE(f), t, a)

  /* Recrusive blocks need to be declared before used. */
  #define RECURSIVE_NESTED_FUNC(return_type, function_name, \
                      arg_types, arg_types_and_names) \
    __BLOCK return_type (^function_name) arg_types; \
    function_name = ^ return_type arg_types_and_names

  #define INLINE_RECURSIVE_NESTED_FUNC(r, f, t, a) \
    RECURSIVE_NESTED_FUNC (r, f, t, a)

  #define INLINE_INTUSE_RECURSIVE_NESTED_FUNC(r, f, t, a) \
    RECURSIVE_NESTED_FUNC (r, INTUSE(f), t, a)

#else /* gcc nested function */

  #define __BLOCK

  #define NESTED_FUNC(return_type, function_name, \
                      arg_types, arg_types_and_names) \
    return_type function_name arg_types_and_names

  #define INLINE_NESTED_FUNC(r, f, t, a) \
    inline NESTED_FUNC (r, f, t, a)

  #define INLINE_INTUSE_NESTED_FUNC(r, f, t, a) \
    inline NESTED_FUNC (r, INTUSE(f), t, a)

  #define RECURSIVE_NESTED_FUNC(r, f, t, a) \
    NESTED_FUNC (r, f, t, a)

  #define INLINE_RECURSIVE_NESTED_FUNC(r, f, t, a) \
    inline RECURSIVE_NESTED_FUNC (r, f, t, a)

  #define INLINE_INTUSE_RECURSIVE_NESTED_FUNC(r, f, t, a) \
    INLINE_RECURSIVE_NESTED_FUNC (r, INTUSE(f), t, a)

#endif

#endif /* _NESTED_FUNC_H */

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Compile elfutils with Clang
  2017-09-09 10:53 Compile elfutils with Clang Dmitry Golovin
       [not found] ` <CAEk9T_1jS-JmN6Ef+5ncsGodgK4oT7FwAu9C5PZCgoPJFPhcNg@mail.gmail.com>
@ 2017-09-19 14:27 ` Mark Wielaard
  1 sibling, 0 replies; 5+ messages in thread
From: Mark Wielaard @ 2017-09-19 14:27 UTC (permalink / raw)
  To: Dmitry Golovin, chh, elfutils-devel

Hi Dmitry,

On Sat, 2017-09-09 at 13:52 +0300, Dmitry Golovin wrote:
> I've been trying to compile elfutils with clang for a while now and
> I'm wondering maybe someone else is also working on it?
> I found some useful patches written by Chih-Hung Hsieh, but they seem
> to be written over 2 years ago and not maintained.
> Is there a fork or a branch of elfutils that can be compiled with
> clang?

The problem with clang is that it claims to implement -std=gnu99 but
doesn't really. We now have a configure check to make sure the features
used in the code base are actually supported by the compiler. So as
soon as clang gets the needed features it should just work.

Various people have worked on supporting clang as compiler, but it is a
lot of work and nobody succeeded doing it without making the code much 
harder to maintain. But in general elfutils patches to clean up the
code and support alternative compilers (or linkers, libc, kernels,
etc.) are accepted and integrated as long as they improve the code base
and don't make it hard to maintain. But the first target of elfutils is
a normal GNU/Linux system.

You might want to look at the mailinglist archives to find various
attempts. Including a discussion of replacing nested functions with
blocks. Which wasn't accepted because nobody seemed to believe it
actually improved the code.

Cheers,

Mark

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2017-09-19 14:27 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-09-09 10:53 Compile elfutils with Clang Dmitry Golovin
     [not found] ` <CAEk9T_1jS-JmN6Ef+5ncsGodgK4oT7FwAu9C5PZCgoPJFPhcNg@mail.gmail.com>
2017-09-12 13:09   ` Dmitry Golovin
2017-09-12 14:32     ` Ulf Hermann
2017-09-12 15:25       ` Dmitry Golovin
2017-09-19 14:27 ` Mark Wielaard

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).