- list of procedure descriptors (PDR). The address in the FDR
- is the absolute address of the first procedure. The address
- in the first PDR gives the offset of that procedure relative
- to the object file's base-address. The addresses in
- subsequent PDRs specify each procedure's address relative to
- the object file's base-address. To make things more juicy,
- whenever the PROF bit in the PDR is set, the real entry point
- of the procedure may be 16 bytes below what would normally be
- the procedure's entry point. Instead, DEC came up with a
- wicked scheme to create profiled libraries "on the fly":
- instead of shipping a regular and a profiled version of each
- library, they insert 16 bytes of unused space in front of
- each procedure and set the "prof" bit in the PDR to indicate
- that there is a gap there (this is done automagically by "as"
- when option "-pg" is specified). Thus, normally, you link
- against such a library and, except for lots of 16 byte gaps
- between functions, things will behave as usual. However,
- when invoking "ld" with option "-pg", it will fill those gaps
- with code that calls mcount(). It then moves the function's
- entry point down by 16 bytes, and out pops a binary that has
- all functions profiled.
-
- NOTE: Neither FDRs nor PDRs are strictly sorted in memory
- order. For example, when including header-files that
- define functions, the FDRs follow behind the including
- file, even though their code may have been generated at
- a lower address. File coff-alpha.c from libbfd
- illustrates this (use "odump -PFv" to look at a file's
- FDR/PDR). Similarly, PDRs are sometimes out of order
- as well. An example of this is OSF/1 v3.0 libc's
- malloc.c. I'm not sure why this happens, but it could
- be due to optimizations that reorder a function's
- position within an object-file.
-
- Strategy:
-
- On the first call to this function, we build a table of FDRs
- that is sorted by the base-address of the object-file the FDR
- is referring to. Notice that each object-file may contain
- code from multiple source files (e.g., due to code defined in
- include files). Thus, for any given base-address, there may
- be multiple FDRs (but this case is, fortunately, uncommon).
- lookup(addr) guarantees to return the first FDR that applies
- to address ADDR. Thus, after invoking lookup(), we have a
- list of FDRs that may contain the PDR for ADDR. Next, we
- walk through the PDRs of these FDRs and locate the one that
- is closest to ADDR (i.e., for which the difference between
- ADDR and the PDR's entry point is positive and minimal).
- Once, the right FDR and PDR are located, we simply walk
- through the line-number table to lookup the line-number that
- best matches ADDR. Obviously, things could be sped up by
- keeping a sorted list of PDRs instead of a sorted list of
- FDRs. However, this would increase space requirements
- considerably, which is undesirable. */
+ list of procedure descriptors (PDR). The address in the FDR
+ is the absolute address of the first procedure. The address
+ in the first PDR gives the offset of that procedure relative
+ to the object file's base-address. The addresses in
+ subsequent PDRs specify each procedure's address relative to
+ the object file's base-address. To make things more juicy,
+ whenever the PROF bit in the PDR is set, the real entry point
+ of the procedure may be 16 bytes below what would normally be
+ the procedure's entry point. Instead, DEC came up with a
+ wicked scheme to create profiled libraries "on the fly":
+ instead of shipping a regular and a profiled version of each
+ library, they insert 16 bytes of unused space in front of
+ each procedure and set the "prof" bit in the PDR to indicate
+ that there is a gap there (this is done automagically by "as"
+ when option "-pg" is specified). Thus, normally, you link
+ against such a library and, except for lots of 16 byte gaps
+ between functions, things will behave as usual. However,
+ when invoking "ld" with option "-pg", it will fill those gaps
+ with code that calls mcount(). It then moves the function's
+ entry point down by 16 bytes, and out pops a binary that has
+ all functions profiled.
+
+ NOTE: Neither FDRs nor PDRs are strictly sorted in memory
+ order. For example, when including header-files that
+ define functions, the FDRs follow behind the including
+ file, even though their code may have been generated at
+ a lower address. File coff-alpha.c from libbfd
+ illustrates this (use "odump -PFv" to look at a file's
+ FDR/PDR). Similarly, PDRs are sometimes out of order
+ as well. An example of this is OSF/1 v3.0 libc's
+ malloc.c. I'm not sure why this happens, but it could
+ be due to optimizations that reorder a function's
+ position within an object-file.
+
+ Strategy:
+
+ On the first call to this function, we build a table of FDRs
+ that is sorted by the base-address of the object-file the FDR
+ is referring to. Notice that each object-file may contain
+ code from multiple source files (e.g., due to code defined in
+ include files). Thus, for any given base-address, there may
+ be multiple FDRs (but this case is, fortunately, uncommon).
+ lookup(addr) guarantees to return the first FDR that applies
+ to address ADDR. Thus, after invoking lookup(), we have a
+ list of FDRs that may contain the PDR for ADDR. Next, we
+ walk through the PDRs of these FDRs and locate the one that
+ is closest to ADDR (i.e., for which the difference between
+ ADDR and the PDR's entry point is positive and minimal).
+ Once, the right FDR and PDR are located, we simply walk
+ through the line-number table to lookup the line-number that
+ best matches ADDR. Obviously, things could be sped up by
+ keeping a sorted list of PDRs instead of a sorted list of
+ FDRs. However, this would increase space requirements
+ considerably, which is undesirable. */