Στις Πέμ, 16 Αυγ 2018 στις 2:17 π.μ., ο/η William Brown <william@blackhats.net.au> έγραψε:
On Wed, 2018-08-15 at 22:36 +0300, Ilias Stamatis wrote:
> Hi everyone,
>
> As I'm going through the code I noticed that some functions have the
> ESECT macro in their signature. Here's how ESECT is defined:
>
> /** Put infrequently used env functions in separate section */
> # ifdef __APPLE__
> #  define   ESECT   __attribute__ ((section("__TEXT,text_env")))
> # else
> #  define   ESECT   __attribute__ ((section("text_env")))
> # endif
>
> So, to my understanding those pieces of code / functions are put in a
> separate binary section other than the standard "text" section that
> they would end up normally. The comment says that this applies to
> infrequently used functions.
>
> I suspect this has something to do with caching but I'm not sure how
> it helps exactly. Could someone please clarify this?

The idea is that anying in this section will be placed in a seperate
section in the resulting ELF, so that functions used at "startup" are
residing in different pages to those used during common run times. The
objective is to minimise polution of the L1i/L2/L3 cache's with code
that "isn't used" frequently. Because x86_64 is a Von Neumann
architecture (compared to a Harvard one), cache is shared for
instructions and data, so minimising our cache footprint means more
data in cache instead :)

At first I thought that if this code is ever accessed it will end up in the cache anyway. Because code or data transfers from RAM to cache in cache blocks / cache lines of fixed width (64 bytes), irrespectively of which section of the binary it belongs to or anything like that. And that's why I asked.

But then I realized that infrequently used code could happen to be adjacent to frequently used code in the same 64-byte block, thus remaining in the cache "forever" and that is probably what you refer to by "cache pollution".

So I suppose it's about that.

Thanks for the answer!
 

As to it's effectiveness, I can not comment without having benchmarked
the code. I suspect it's a micro-optimisation, but not one that has
harmful effects on the rest of the code base, so it's continued use
does not concern me greatly. A really great explanation of "why" C
programmers would add such definitions is this discussed here
specifically:

"...implementations of C have had to become increasingly complex to
maintain the illusion that C maps easily to the underlying hardware and
gives fast code."

https://queue.acm.org/detail.cfm?id=3212479

As a result, speculating on our C and how it translates to real machine
behaviour is a very complex topic, and likely one we should not bother
with - it's all a lie anyway.

If you want to read the authorative source of DSO improvements, this
paper by Ulrich Drepper (He writes amazing content, and was a major
contributor to glibc) suggests different approaches:

https://www.akkadia.org/drepper/dsohowto.pdf

The short summary is "minismise your exposed api as much as possible".
I see no mention of optimising section placement of code here.

Other languages also do nothing with section optimisation: Rust, Erlang
and others do not bother.

Perhaps we should also not bother.

--
Sincerely,

William