Hi,

I started to look at profiling using utrace(2), so I played a bit with cc -pg.
But the whole mail will be about -current without any patches.

While trying a very simple C file to play with, I found several problems when 
building with cc -pg (to enable profil instrumentation).

$ cat test.c
#include <stdio.h>
int
main()
{
        printf("hello world\n");
        return 0;
}

$ cc test.c && ./a.out
hello world
$ cc -pg test.c && ./a.out
Segmentation fault (core dumped)

This particular segfault comes from ld.so.

$ egdb ./a.out
(gdb) r
Starting program: /tmp/a/a.out 

Program received signal SIGSEGV, Segmentation fault.
_dl_boot (argv=<optimized out>, envp=<optimized out>, dyn_loff=11309662208, 
dl_data=0x720905e97fd0) at /usr/src/libexec/ld.so/loader.c:586
586             exe_obj->load_list = load_list;
(gdb) bt
#0  _dl_boot (argv=<optimized out>, envp=<optimized out>, dyn_loff=11309662208, 
dl_data=0x720905e97fd0) at /usr/src/libexec/ld.so/loader.c:586
#1  0x00000002a21c07f6 in _dl_start () at 
/usr/src/libexec/ld.so/amd64/ldasm.S:61
#2  0x0000000000000000 in ?? ()


If I correctly understood the problem, it is because a.out is a dynamic program 
(no -static on command line), but compiled only with static libraries, so it is 
without .dynamic section.

$ cc -v -pg test.c
OpenBSD clang version 13.0.0
Target: amd64-unknown-openbsd7.3
Thread model: posix
InstalledDir: /usr/bin
 "/usr/bin/cc" -cc1 -triple amd64-unknown-openbsd7.3 -emit-obj -mrelax-all 
-disable-free -disable-llvm-verifier -discard-value-names -main-file-name 
test.c -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all 
-relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables 
-target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature 
+retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -v 
-fcoverage-compilation-dir=/tmp/a -resource-dir /usr/lib/clang/13.0.0 
-internal-isystem /usr/lib/clang/13.0.0/include -internal-externc-isystem 
/usr/include -fdebug-compilation-dir=/tmp/a -ferror-limit 19 -pg -fwrapv 
-stack-protector 2 -fgnuc-version=4.2.1 -fno-builtin-malloc -fno-builtin-calloc 
-fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup 
-fno-builtin-strndup -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o 
/tmp/test-1efcc1.o -x c test.c
clang -cc1 version 13.0.0 based upon LLVM 13.0.0 default target 
amd64-unknown-openbsd7.3
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/clang/13.0.0/include
 /usr/include
End of search list.
 "/usr/bin/ld" -e __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/test-1efcc1.o -lcompiler_rt -lc_p -lcompiler_rt 
/usr/lib/crtend.o


When using -pg, instead of linking to -lc, it is using -lc_p which only exists 
as libc_p.a.

The linker has no dynamic library to register and seems to no include any 
.dynamic section.

$ readelf -d a.out                                                              
                                          

There is no dynamic section in this file.


But ld.so seems to assumes that .dynamic will exists.

exe_obj is initialized when .dynamic is found (PT_DYNAMIC), and used 
unconditionnally later.

src/libexec/ld.so/loader.c
   542                  case PT_DYNAMIC:
   543                          minva = TRUNC_PG(minva);
   544                          maxva = ROUND_PG(maxva);
   545                          exe_obj = _dl_finalize_object(argv[0] ? argv[0] 
: "",
   546                              (Elf_Dyn *)(phdp->p_vaddr + exe_loff),
   547                              (Elf_Phdr *)dl_data[AUX_phdr],
   548                              dl_data[AUX_phnum], OBJTYPE_EXE, minva + 
exe_loff,
   549                              exe_loff);
   550                          _dl_add_object(exe_obj);
   551                          break;
...
   586          exe_obj->load_list = load_list;
   587          exe_obj->obj_flags |= DF_1_GLOBAL;
   588          exe_obj->nodelete = 1;
   589          exe_obj->load_size = maxva - minva;
   590          exe_obj->relro_addr = relro_addr;
   591          exe_obj->relro_size = relro_size;

The segfault is at line 586 (at first exe_obj deferences).


If the program is built with a (unused) dynamic library, it is (somehow) fine: 
exe_obj is properly initialized and _dl_boot is fine.

$ cc -pg -lm test.c
$ readelf -d a.out

Dynamic section at offset 0x1acb8 contains 18 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libm.so.10.1]
 0x0000000000000015 (DEBUG)              0x0
 0x0000000000000007 (RELA)               0x2007b8
 0x0000000000000008 (RELASZ)             48 (bytes)
 0x0000000000000009 (RELAENT)            24 (bytes)
 0x0000000000000017 (JMPREL)             0x2007e8
 0x0000000000000002 (PLTRELSZ)           24 (bytes)
 0x0000000000000003 (PLTGOT)             0x21ce50
 0x0000000000000014 (PLTREL)             RELA
 0x0000000000000006 (SYMTAB)             0x200348
 0x000000000000000b (SYMENT)             24 (bytes)
 0x0000000000000005 (STRTAB)             0x2006c4
 0x000000000000000a (STRSZ)              244 (bytes)
 0x000000006ffffef5 (GNU_HASH)           0x200570
 0x0000000000000004 (HASH)               0x200604
 0x0000000000000020 (PREINIT_ARRAY)      0x21c6b8
 0x0000000000000021 (PREINIT_ARRAYSZ)    0x8
 0x0000000000000000 (NULL)               0x0


Now, at runtime, it segfaults later but for another reason.

$ a.out
Segmentation fault (core dumped) 

$ dmesg | tail -1
[a.out]34943/523783 pc=218a32 inside 2c72e0000-2c72ebfff: bogus syscall

$ egdb ./a.out
Program received signal SIGSEGV, Segmentation fault.
issetugid () at /tmp/-:3
3       /tmp/-: No such file or directory.
(gdb) bt
#0  issetugid () at /tmp/-:3
#1  0x00000000002056ac in _libc_preinit (argc=<optimized out>, argv=<optimized 
out>, envp=<optimized out>, cb=<error reading variable: Cannot access memory at 
address 0x87c52af645eebfa7>) at /usr/src/lib/libc/dlfcn/init.c:128
Backtrace stopped: Cannot access memory at address 0x87c52af645eebfdf
(gdb) disassemble 
Dump of assembler code for function issetugid:
   0x0000000000218a10 <+0>:       push   rbp
   0x0000000000218a11 <+1>:       lea    rbp,[rsp]
   0x0000000000218a15 <+5>:       call   0x205eb0 <__mcount>
   0x0000000000218a1a <+10>:      pop    rbp
   0x0000000000218a1b <+11>:      mov    r11,QWORD PTR [rip+0x3c06]        # 
0x21c628 <__retguard__thread_sys_issetugid>
   0x0000000000218a22 <+18>:      xor    r11,QWORD PTR [rsp]
   0x0000000000218a26 <+22>:      push   r11
   0x0000000000218a28 <+24>:      mov    eax,0xfd
   0x0000000000218a2d <+29>:      mov    r10,rcx
   0x0000000000218a30 <+32>:      syscall 
=> 0x0000000000218a32 <+34>:      pop    r11
   0x0000000000218a34 <+36>:      xor    r11,QWORD PTR [rsp]
   0x0000000000218a38 <+40>:      cmp    r11,QWORD PTR [rip+0x3be9]        # 
0x21c628 <__retguard__thread_sys_issetugid>
   0x0000000000218a3f <+47>:      je     0x218a4c <issetugid+60>
   0x0000000000218a41 <+49>:      int3   
   0x0000000000218a42 <+50>:      int3   
   0x0000000000218a43 <+51>:      int3   
   0x0000000000218a44 <+52>:      int3   
   0x0000000000218a45 <+53>:      int3   
   0x0000000000218a46 <+54>:      int3   
   0x0000000000218a47 <+55>:      int3   
   0x0000000000218a48 <+56>:      int3   
   0x0000000000218a49 <+57>:      int3   
   0x0000000000218a4a <+58>:      int3   
   0x0000000000218a4b <+59>:      int3   
   0x0000000000218a4c <+60>:      ret    
End of assembler dump.


>From my understanding, the `syscall` isn't permitted because it comes from the 
static library libc_p.a inside the dynamic program a.out.

Thanks.
-- 
Sebastien Marie

Reply via email to