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