0

Take a look at how perf works, user can use command like "perf record -e cpu-clock ./binary" to run the binary and get information. Does perf load the binary, make some config and then running it? If it is true, could I get virtual address of some code by looking at the /proc/pid/maps? I am a rookie in binary execution and hope for your advice!

qunqunqun
  • 3
  • 3

1 Answers1

0

Could I load elf and get virtual address from /proc/pid/maps before actually running it?

No. The address space is built as the program runs. "Memory mapping" is a process (of software being run and requesting memory mappings), not a property of the binary file. This becomes doubly clear now that basically all mainstream operating systems use address space layout randomization (ASLR)!

Often, a lot of that is done before your C main() even runs - by the loader (ld.so on Linux), but that's still executing code from your binary.

What your ELF file does contain are sections which can be loaded at fixed addresses, but as said, ASLR makes that rare. Much of the code compiled these days is relocateable, so all it needs is to know is relative addresses.

Your question regarding perf record is unrelated, but what perf does is set up some kernel-space observables (using, mostly, eBPF) and then quite regularly executing the binary, while probing said observables.

Marcus Müller
  • 34,677
  • 4
  • 53
  • 94
  • It is actually possible to get the **virtual** address from the elf header – alinsoar Nov 24 '21 at 12:53
  • 1
    @alinsoar hm, in PIE object files, there's no fixed virtual address; it's all relative to values in the global offset table. See, for example, https://stackoverflow.com/questions/38189169/elf-pie-aslr-and-everything-in-between-specifically-within-linux – Marcus Müller Nov 24 '21 at 12:55
  • 1
    @alinsoar: yes, for a non-PIE executable, but you of course can't get it from `/proc//maps` like the question is asking unless there's a process actually executing this ELF executable. (You can use `ptrace` to have that process stop before the first user-space instruction, [like GDB uses to implement `starti`](https://stackoverflow.com/questions/69762022/how-does-gdb-start-an-assembly-compiled-program-and-step-one-line-at-a-time).) – Peter Cordes Nov 24 '21 at 13:30
  • @Marcus: *by the loader (ld.so on Linux)* - I'm pretty sure the kernel's ELF program loader still maps a dynamic executable as well as the ELF interpeter's (`ld.so`'s) own text/data segments. If you `strace /bin/true` for example, you see system calls made by `ld.so`, and they don't include `open` / `mmap` of the executable. Only of `libc.so.6`. Also, if you use GDB to `starti` on it, you stop before the first instruction of `ld.so`'s `_start`. And even at that point, you'd see mappings for the program's own segments as well as ld.so in `/proc//maps`. – Peter Cordes Nov 24 '21 at 13:35
  • What `perf record` actually does for hardware PMU events like `cycles` and `instructions` is use `perf_event_open` to have the kernel use HW perf counters. The kernel saves/restores them on context switch. Those counters overflow when reaching the programmed point, causing an interrupt or causing the CPU to record a sample into a small buffer (for "precise events" on modern x86). It's not a matter of asynchronously sampling them, unless you're looking at software events. Oh, but the question specified `-e cpu-clock` which is software, not `cycles` or `uops_issued.any` or other HW events. – Peter Cordes Nov 24 '21 at 13:41
  • @MarcusMüller : Thanks for your great answer! By the way, could give me some advice about get the vaddr of some user code after actually running the binary? – qunqunqun Nov 25 '21 at 06:34
  • @PeterCordes: **And even at that point, you'd see mappings for the program's own segments as well as ld.so in /proc//maps.** So does there exist some easy ways to do such things? – qunqunqun Nov 25 '21 at 06:37
  • @qunqunqun: By forking a new process, using `ptrace(PTRACE_TRACEME)`, and execing the executable, yes, like GDB does ([How does gdb start an assembly compiled program and step one line at a time?](https://stackoverflow.com/q/69762022)). It normally makes more sense to just parse the ELF program headers directly out of the binary, though, especially because another run of a PIE executable will randomly choose a different base address. So you probably want to know whether it's a PIE or not. Whether any of that is useful depends on what problem you're trying to solve. – Peter Cordes Nov 25 '21 at 07:04