Re: Questions about a symbol in `libc.so`

From: Andrei Lascu <alas.20073_at_gmail.com>
Date: Thu, 11 Apr 2024 13:42:47 UTC
Hello again. Just to update my previous question, I did manage to 
eventually figure out where the relocation was hidden. I was aware of a 
number of relocation that seemed odd, and I put them on the side, 
thinking I might either have to figure them later, or they might just be 
some artifact. Well, the relocation I needed was hidden among them:

Relocation section '.rela.dyn' at offset 0x2abf8 contains 2605 entries:
   Offset          Info           Type           Sym. Value    Sym. Name 
+ Addend
0000001d6888  000000000403 R_AARCH64_RELATIV 13416c
0000001d6890  000000000403 R_AARCH64_RELATIV 8b268
0000001d6898  000000000403 R_AARCH64_RELATIV 178108
0000001d68a0  000000000403 R_AARCH64_RELATIV 8b240
0000001d68a8  000000000403 R_AARCH64_RELATIV 15ac9c
0000001d68b0  000000000403 R_AARCH64_RELATIV 49b29
0000001d68c0  000000000403 R_AARCH64_RELATIV 45bfe

The reason I thought them odd was because they had no symbol attached to 
them, just raw addressed. However, one of these offsets actually did 
match what the system loader was relocating against my mystery 
`__sdidinit`. So the solution was rather simple, ensure I relocate the 
addend into the offset, as there is no symbol value here, and I am on my 
way. There are still some odd issues here, like why are these 
relocations not referencing a symbol, when seemingly they should, and 
why it seems these resolve via `R_AARCH64_GLOB_DAT` at runtime, rather 
than via `R_AARCH64_RELATIVE` in `/libexec/rtld-elf/aarch64/reloc.c`, 
but I think as long as I am making progress, I'll let these questions 
get answered another time.

Regards,
Andrei.

On 09/04/2024 12:15, Andrei Lascu wrote:
> Hello. Due to certain circumstances, I am currently working on a 
> loader-like application for shared object files to be ran on a system 
> running an OS derived from FreeBSD. I've got most of the stuff working 
> to the level I need, but I've found something in `libc.so.7` that's 
> got me stumped.
>
> The goal is to run a test file that, among others, calls `fdopen` from 
> `libc.so`. Everything runs well, until line 124 in `findfp.c` is hit 
> (as per the source for `libc.so` in FreeBSD 14 Stable), where 
> `__sdidinit` is accessed. In my loader, there is no memory allocated 
> for this variable, because there is no relocation entry for it. Here 
> is where my confusion starts.
>
> Looking at the symbol table for `libc.so`, `__sdidinit` is a `LOCAL 
> DEFAULT` [1] symbol. The only way I can think of to replicate that 
> behaviour is to declare a variable static. However, the variable is 
> declared as `int __sdidinit` in `findfp.c` (and also as `extern int 
> __sdidinit` in `stdio/local.h`, which again, looks odd), which to me 
> should mean it's a `GLOBAL` symbol (unless there is some weird linking 
> stuff I didn't manage to hunt down during compilation). Furthermore, 
> running the program through the system runtime loader (and also 
> looking at the compiled assembly), accessing the variable seems to be 
> done to what I 90% believe is a GOT lookup. However, with no 
> relocation entry, I'm completely unsure how this is the case.
>
> My questions are as follows:
> 1) Is it possible to access a variable via a GOT lookup when a 
> relocation entry does not exist?
> 2) Is there some explanation as to how this variable gets `LOCAL` 
> binding?
> 3) Is perhaps the system loader doing some special thing because it 
> considers `libc.so` especially, and it brings some relocation entries 
> from somewhere else, or has some default ones?
> 4) A side question: while the symbol exists in `libc.so.7.full`, after 
> doing a `make buildworld`, it seems to be stripped out of `libc.so.7` 
> itself - I'm wondering if this is some optimization at work.
>
> Thanks in advance for your help, and apologies if this was the wrong 
> mailing list to ask.
>
> Regards,
> Andrei.
>
> [1] I should mention I had a look at OpenBSD's `libc.so`, which was 
> the other `libc.so` that I found with this symbol. In there, the main 
> difference is that `__sdidinit` is `LOCAL HIDDEN`, which, if some 
> similar mechanism might be employed in FreeBSD, might explain 2) and 
> 4) above, but I'm still unsure where to look.
>
>