Of course, all programs compiled without '-pg' work fine for me.
I found this issue when I profile my application with gprof(1).
For example, following example C source code fails to execute on OpenBSD 7.0.

```
$ cat helloworld.c
#include <stdio.h>
int main(int argc, char *argv[])
{
        printf("Hello World!\n");
        return 0;
}
$ cc helloworld.c
$ ./a.out
Hello World!
$ cc -pg helloworld.c
$ ./a.out
Segmentation fault (core dumped)
$ readelf -h -l -d -u ./a.out
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x2045f0
  Start of program headers:          64 (bytes into file)
  Start of section headers:          419600 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         11
  Size of section headers:           64 (bytes)
  Number of section headers:         29
  Section header string table index: 27

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000200040 0x0000000000200040
                 0x0000000000000268 0x0000000000000268  R      8
  INTERP         0x00000000000002a8 0x00000000002002a8 0x00000000002002a8
                 0x0000000000000013 0x0000000000000013  R      1
      [Requesting program interpreter: /usr/libexec/ld.so]
  LOAD           0x0000000000000000 0x0000000000200000 0x0000000000200000
                 0x00000000000035ec 0x00000000000035ec  R      1000
  LOAD           0x00000000000035f0 0x00000000002045f0 0x00000000002045f0
                 0x000000000001563e 0x000000000001563e  R E    1000
  LOAD           0x0000000000018c30 0x000000000021ac30 0x000000000021ac30
                 0x0000000000000700 0x0000000000000700  RW     1000
  LOAD           0x0000000000019330 0x000000000021c330 0x000000000021c330
                 0x0000000000001028 0x0000000000006a38  RW     1000
  GNU_RELRO      0x0000000000018c30 0x000000000021ac30 0x000000000021ac30
                 0x0000000000000700 0x00000000000013d0  R      1
  GNU_EH_FRAME   0x00000000000017a8 0x00000000002017a8 0x00000000002017a8
                 0x00000000000004bc 0x00000000000004bc  R      4
  OPENBSD_RANDOM 0x0000000000018c30 0x000000000021ac30 0x000000000021ac30
                 0x0000000000000068 0x0000000000000068  RW     8
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     0
  NOTE           0x00000000000002bc 0x00000000002002bc 0x00000000002002bc
                 0x0000000000000018 0x0000000000000018  R      4

 Section to Segment mapping:
  Segment Sections...
   00
   01     .interp
   02     .interp .note.openbsd.ident .rodata .eh_frame_hdr .eh_frame
   03     .text .init .fini
   04     .openbsd.randomdata .jcr .ctors .dtors .preinit_array .data.rel.ro 
.got
   05     .data .bss
   06     .openbsd.randomdata .jcr .ctors .dtors .preinit_array .data.rel.ro 
.got
   07     .eh_frame_hdr
   08     .openbsd.randomdata
   09
   10     .note.openbsd.ident

There is no dynamic section in this file.

There are no unwind sections in this file.
```

I can see the compiled program is statically linked (Type: EXEC),
and has an INTERP section (/usr/libexec/ld.so), and no dynamic sections.

If a elf binary has an INTERP section, the kernel invokes dynamic linker 
(ld.so).
Ld.so tries to link dynamic link libraries, but it fails because no dynamic
sections in the elf binary.

In 'src/libexec/ld.so/loader.c', `_dl_boot` function reads a dynamic section and
initialize `exe_obj` pointer. If there is no dynamic sections, `exe_obj` is 
still `NULL`.
After reading header sections, `exe_obj` is referred to store parsed values,
and it fails by NULL pointer access.

```
501        exe_obj = NULL;

(snip)

511        for (loop = 0; loop < dl_data[AUX_phnum]; loop++) {
512                switch (phdp->p_type) {
513                case PT_PHDR:
514                        exe_loff = (Elf_Addr)dl_data[AUX_phdr] - 
phdp->p_vaddr;
515                        us += exe_loff;
516                        DL_DEB(("exe load offset:  0x%lx\n", exe_loff));
517                        break;
518                case PT_DYNAMIC:
519                        minva = TRUNC_PG(minva);
520                        maxva = ROUND_PG(maxva);
521                        exe_obj = _dl_finalize_object(argv[0] ? argv[0] : "",
522                            (Elf_Dyn *)(phdp->p_vaddr + exe_loff),
523                            (Elf_Phdr *)dl_data[AUX_phdr],
524                            dl_data[AUX_phnum], OBJTYPE_EXE, minva + 
exe_loff,
525                            exe_loff);
526                        _dl_add_object(exe_obj);
527                        break;

(snip)

562        exe_obj->load_list = load_list;
563        exe_obj->obj_flags |= DF_1_GLOBAL;
564        exe_obj->load_size = maxva - minva;
565        exe_obj->relro_addr = relro_addr;
566        exe_obj->relro_size = relro_size;
```

I wonder why statically linked binary has an INTERP section?
I tried checking which options are passed to 'ld'.
I replaced my '/usr/bin/ld' as following script.

```
#!/bin/sh

echo $*
exec /usr/bin/ld.lld $*
```

I ran `cc -pg` again.

```
$ cc -pg helloworld.c
__start --eh-frame-hdr -Bdynamic -dynamic-linker /usr/libexec/ld.so -nopie -o 
a.out /usr/lib/gcrt0.o /usr/lib/crtbegin.o -L/usr/lib /tmp/helloworld-59ced4.o 
-lcompiler_rt -lc_p -lcompiler_rt /usr/lib/crtend.o
```

`-Bdynamic -dynamic-linker /usr/libexec/ld.so` is passed to the 'ld'.
I think 'ld' is not wrong, passing the dynamic linker option seems to be a bug.

I patched clang source code to pass `-Bstatic` option as follows.
I can confirm my programs compiled with -pg option run successfully.

```
diff --git a/gnu/llvm/clang/lib/Driver/ToolChains/OpenBSD.cpp 
b/gnu/llvm/clang/lib/Driver/ToolChains/OpenBSD.cpp
index 1577f70aad6..c3a2f9e005e 100644
--- a/gnu/llvm/clang/lib/Driver/ToolChains/OpenBSD.cpp
+++ b/gnu/llvm/clang/lib/Driver/ToolChains/OpenBSD.cpp
@@ -108,25 +108,25 @@ void openbsd::Linker::ConstructJob(Compilation &C, const 
JobAction &JA,

   if (ToolChain.getArch() == llvm::Triple::mips64)
     CmdArgs.push_back("-EB");
   else if (ToolChain.getArch() == llvm::Triple::mips64el)
     CmdArgs.push_back("-EL");

   if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) {
     CmdArgs.push_back("-e");
     CmdArgs.push_back("__start");
   }

   CmdArgs.push_back("--eh-frame-hdr");
-  if (Args.hasArg(options::OPT_static)) {
+  if (Args.hasArg(options::OPT_static) || Args.hasArg(options::OPT_pg)) {
     CmdArgs.push_back("-Bstatic");
   } else {
     if (Args.hasArg(options::OPT_rdynamic))
       CmdArgs.push_back("-export-dynamic");
     CmdArgs.push_back("-Bdynamic");
     if (Args.hasArg(options::OPT_shared)) {
       CmdArgs.push_back("-shared");
     } else {
       CmdArgs.push_back("-dynamic-linker");
       CmdArgs.push_back("/usr/libexec/ld.so");
     }
   }
```

Is it OK?

--
Yuichiro NAITO ([email protected])

Reply via email to