Page 1 of 1

How to execute dynamically loaded .init section?

Posted: Tue Dec 17, 2024 9:37 am
by AndrewAPrice
I'm implementing dynamic loading of libraries. I have the .init and .fini sections loaded into memory.

.init_array and .fini_array are easy because they're just a list of functions, but .init and .fini appears to be code to execute:

Code: Select all

Disassembly of section .init:

000000000000ecbc <.init>:
    ecbc: e8 af f8 ff ff               	call	0xe570 <__fixunssfti+0x80>

Disassembly of section .fini:

000000000000ecc1 <.fini>:
    ecc1: e8 fa f8 ff ff               	call	0xe5c0 <__fixunssfti+0xd0>
I can't just call .init as if it were a function, because there is no `ret`, so it keeps on executing into .fini, and then into the next section (.plt) and eventually crashes.

I was thinking of copying this code somewhere and putting a `ret` opcode so it's a callable function, but "e8" is near call relative (because the dynamically loaded library is position independent code), so I'd have to patch up any PIC I'd copy.

Surely there is an easier way? Can I force Clang/LLD to make .init not be a naked function (so it returns to the caller?) How are dynamic loaders suppose to execute the code in .init?

Re: How to execute dynamically loaded .init section?

Posted: Tue Dec 17, 2024 11:28 am
by Octocontrabass
It's missing the "ret" opcode because it wasn't linked against the appropriate startup code.

But, if you don't need binary compatibility with another OS, you can configure your compiler to use .init_array/.fini_array for everything and ignore the .init, .fini, .ctors, and .dtors sections.

Re: How to execute dynamically loaded .init section?

Posted: Wed Dec 18, 2024 12:47 am
by nullplan
As Octo said, the start files weren't linked in. Normally, you have a crti.o that is typically the result of compiling something like this:

Code: Select all

.section ".init","ax",@progbits
.global_init
.type _init, @function
_init:
  pushq %rax # just some code because having the section be empty can trigger corner-case bugs in linkers.
  
 .section ".fini","ax",@progbits
 .global _fini
 .type _fini, @function
 _fini:
   pushq %rax
Then you also have a crtn.o at the end that contains something like this

Code: Select all

.section ".init","ax",@progbits
  popq %rax
  ret
  
.section ".fini","ax",@progbits
   popq
   ret
And normally you place crti.o at the start of the linker command line and crtn.o at the end. And then hope that nobody added a command line switch that makes the linker re-order its input sections.

Alternatively, you can just sod the entire .init and .fini section and only use .init_array and .fini_array, because the year starts with 20 and nobody uses .init and .fini seriously anymore. The entire mechanism violates the assumption that input sections are independent of each other, and I have seen linkers put the _init label after the ret instruction before. That was one of those corner-case bugs I've alluded to earlier.