Skip to content

Conversation

@kaadam
Copy link
Contributor

@kaadam kaadam commented Aug 12, 2025

Currently Bolt relies on ELF 'e_entry' field or DT_INIT to determine entry point of an ELF file for the instrumentation. There is a case when an ELF file only has DT_INIT_ARRAY/DT_FINI_ARRAY sections, and ELF 'e_entry' holds zero.

@kaadam
Copy link
Contributor Author

kaadam commented Aug 12, 2025

TODO(s):

  • Add test case for DT_INIT_ARRAY
  • Add runtime test for DT_INIT_ARRAY

Previously Bolt relied on ELF 'e_entry' field or DT_INIT to determine
the entry point of an ELF file for the instrumentation.
This PR aims to handle that case if an ELF file only contains
DT_INIT_ARRAY/DT_FINI_ARRAY sections.

Bolt is hooking its runtime function based on e_entry address
if the input is an ELF executable. When the input is a shared object,
Bolt takes address of DT_INIT if that exists. If it doesn't,
Bolt will use DT_INIT_ARRAY for hooking its runtime functions.

This PR follows the implementation of DT_FINI_ARRAY.
@zhouyu0502
Copy link

zhouyu0502 commented Oct 15, 2025

hello i have come across a similar question .
I want to bolt instrument for libc.so.6 (aarch64)
it seems success but when run bin with intrumented libc.so.6, it did not exe _bolt_instr_start() which is in e_entry
i think it is because my libc.so.6 have no DT_INIT and have HasInterpHeader at the same time
how can i fix this ?

@zhouyu0502
Copy link

hello i have applyed for libc.so.6 (have no DT_INIT),but i still failed collect prof because libc.so.6 HasInterpHeader ,SO IN THIS CASE how can i fixed?

@zhouyu0502
Copy link

i have applyed your pr but still failed when using intrumented libc.so.6 in arm64.it seems the father process exited after __bolt_instr_setup and can not exe __bolt_start_trampoline ,i do not know why

@kaadam
Copy link
Contributor Author

kaadam commented Oct 17, 2025

Hi, thanks for your comment and your findings.

Glibc is a tricky Elf shared object. It can acts as a binary or as a shared object.
So libc.so has an entry point which points to '__libc_main' make it directly runnable. It just prints a banner.
File from csu/version.c

extern void __libc_main (void) __attribute__ ((noreturn));

void __libc_main (void)
{
  __libc_print_version ();
  _exit (0);
}

The draft solution what I uploaded, distinguishes between whether the ELF file is a binary or a shared object based on presence of the Interp header.
In this case libc is an so, and it has Interp header, so Bolt just deals with Elf e_entry point which is the __libc_main, and hooking its start runtime function to that. However this never runs if libc acts as SO.

So most probably DT_INITARRAY should be used here (if no DT_INIT), instead of e_entry.
I need to look at this example.

@zhouyu0502
Copy link

zhouyu0502 commented Oct 17, 2025

Hi, thanks for your comment and your findings.

Glibc is a tricky Elf shared object. It can acts as a binary or as a shared object. So libc.so has an entry point which points to '__libc_main' make it directly runnable. It just prints a banner. File from csu/version.c

extern void __libc_main (void) __attribute__ ((noreturn));

void __libc_main (void)
{
  __libc_print_version ();
  _exit (0);
}

The draft solution what I uploaded, distinguishes between whether the ELF file is a binary or a shared object based on presence of the Interp header. In this case libc is an so, and it has Interp header, so Bolt just deals with Elf e_entry point which is the __libc_main, and hooking its start runtime function to that. However this never runs if libc acts as SO.

So most probably DT_INITARRAY should be used here (if no DT_INIT), instead of e_entry. I need to look at this example.

in my case when i apply your pr i have deleted !BC->HasInterpHeader ,
case ELF::DT_INIT_ARRAY
BC->InitArrayAddress = Dyn.getPtr();
break;
case ELF::DT_INIT_ARRAYSZ:
BC->InitArraySize = Dyn.getPtr();

and i found it still cannot exe bin (who use libc.so.6) successfully but i check that it exe __bolt_instr_setup and can not exe __bolt_start_trampoline but when exe _start in libc.so.6 it failed
i dont know why ,thanks for your reply
and i will show more details,wait for me

@zhouyu0502
Copy link

  1. my proposeis to instrument libc.so.6 (arm64) so not bin
  2. i found thatmy origin libc.so.6 do not have INIT (which means cannot exe __boIt_instr_start(),but it have INIT_ARRAY、INIT ARRAYSZ, and PT_INTERP,in order to fix this i have applyed your pr and delete
    (!BC->HaslnterpHeader) in boIt/lib/Rewrite/Rewritelnstance.cpp in case
    DT_INIT and DT_INIT_ARRAY
  3. howerver when i use instrumented libc.so.6 in a exe it still failed to work properliy, i think some went wrong after exe
    bolt_start_trampoline (which means jump to the _start)
    4.feel very confused and want to debug this,can vou tell me how to fix this bug?

@zhouyu0502
Copy link

zhouyu0502 commented Oct 21, 2025

hi ,sorry to interrupt you ,
i attach some information in case you need
1.file libc.so.6
libc.so.6: ELF 64-bit LSB shared object, ARM aarch64, version 1 (GNU/Linux), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, BuildID[sha1]=f5e52c2f342cbaafd253543336b5e0416b7f2b02, for GNU/Linux 3.14.0, with debug_info, not stripped
2.readelf -l libc.so.6
Elf file type is DYN (Shared object file)
Entry point 0x2b330
There are 10 program headers, starting at offset 64
......
INTERP 0x000000000015d198 0x000000000015d198 0x000000000015d198
0x000000000000001b 0x000000000000001b R 0x8
[Requesting program interpreter: /lib/ld-linux-aarch64.so.1]
......
3.readelf -d libc.so.6 | grep INIT
0x0000000000000019 (INIT_ARRAY) 0x19c970
0x000000000000001b (INIT_ARRAYSZ) 24 (bytes)

How

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants