Reputation: 171
I have a header-only library that's currently calling malloc
and free
This header is included in a lot of different static libraries, which are used to build differently configured programs.
I would like to be able to replace those calls with calls into another allocator, at link time -- based on whether that allocator library is included in the link step, without affecting other calls to malloc
and free
.
My idea is to have the library call customizable_malloc
and customizable_free
and have those symbols resolve to malloc
and free
"by default" -- then the allocator library can provide alternate definitions for customizable_malloc
and customizable_free
However, I messed around with weak/alias/weakref attributes and I can't seem to get anything to work. Is there a way to do this?
Note: I know I can create an extra layer of indirection: customizable_malloc
could be a weak alias to a function that calls malloc. But that adds a level of indirection that seems unnecessary.
Ideally, here's the steps I want the linker to take when it comes across a call to customizable_malloc:
Clarifying note: In a single-target scenario, this could be done with #define
. The library could create macros customizable_malloc
and customizable_free
that default to malloc
and free
. However, this doesn't work in this case since things are being built into static libraries without knowledge of whether there's an override.
Upvotes: 0
Views: 1518
Reputation: 213526
You can achieve desired outcome using GNU-ld --defsym option.
Example:
#include <malloc.h>
#include <stdio.h>
void *custom_malloc(size_t sz);
int main()
{
void *p = custom_malloc(1);
void *q = malloc(42); // important: malloc needs to be referenced somewhere
printf("p = %p, q = %p\n", p, q);
return 0;
}
Compiling this with gcc -c t.c
will (naturally) fail to link with unresolved reference to custom_malloc
(if the library providing custom_malloc
is not used):
$ gcc t.o
/usr/bin/ld: t.o: in function `main':
t.c:(.text+0xe): undefined reference to `custom_malloc'
collect2: error: ld returned 1 exit status
Adding --defsym=custom_malloc=malloc
solves this:
$ gcc t.o -Wl,--defsym=custom_malloc=malloc && ./a.out
p = 0x558ca4dc22a0, q = 0x558ca4dc22c0
P.S. If malloc
is not linked into the program (i.e. if I comment out the // important
line), then --defsym
fails:
$ gcc t.c -Wl,--defsym=custom_malloc=malloc && ./a.ou
/usr/bin/ld:--defsym:1: unresolvable symbol `malloc' referenced in expression
...
But that is (I believe) not very relevant to your scenario.
P.P.S. As R correctly stated, the "extra level of indirection" could be a single unconditional JMP malloc
instruction, and the overhead of such indirection is unlikely to be measurable.
Upvotes: 2
Reputation: 215259
The extra level of indirection is the only way to do it. ELF (and other real-world binary format) symbol definition syntax (including for weak symbols) does not provide any way to provide a definition in terms of a reference to an external definition from somewhere else.
Just do the wrapper approach you're considering. It's simple, clean, and relative to the cost of malloc
/free
it's not going to make any big difference in performance.
Upvotes: 2