If the binary is a PIE, exporting functions via the LIEF binary instrumentation framework should allow you to call the function you are interested in as if it was a function in a shared object.
If the binary is dynamically linked and contains code for setting up the standard C runtime environment e.g.
main(), you can hook these functions with LD_PRELOAD and interpose your own code via shared library injection which calls the target function directly with arguments of your choosing.
Using the Qiling emulator, you can record the state of the program and then replay the target function in GDB. Since the code is being emulated, it is straightforward to manipulate any aspect of the process' state (registers, memory, etc.)
Using Frida, Pin, DynamoRIO etc. you can basically make the program do what you want at run time, in this case hook a function, manipulate its arguments and observe the subsequent behavior.
Trampolining with e9patch
e9patch is a static binary rewriting tool that allows one to change/insert code prior to run time.
There are probably even more ways to do this, such as process snapshotting with ptrace and /proc and then manipulating registers and memory with ptrace, emulation with PANDA, emulation with Unicorn, emulation with QEMU, possibly even ELF parasite code or inserting code that calls the target function using LD_PRELOAD together with
__attribute__ ((constructor)) injected_function(). You have a lot of options.