comp.unix.programmer
Re: Get address of function by name at runtime?
gordonb.pxq4j_at_burditt.org (Gordon Burditt) writes:
>> Can something like this be done in Solaris or Linux? i.e. Find the
>> address of a function from a string variable and call it dynamically at
>> run time?
>>
>> void main(void)
>
>Friends don't let friends void main.
>
>There's always the lame, inelegant, slow, but very portable approach:
>make a symbol table with the name of the function in ASCII and a
>function pointer. Then look up the name and use the function
>pointer.
>
>One of the problems with what you want to do, especially if you had
>any ideas of a user typing in the function name, is that there are
>so many functions that you likely don't want the user to type in,
>like main, fread, abort, fork, or signal, or which don't have
>compatible arguments. You might end up needing a symbol table
>anyway to figure out what arguments the function needs.
>
>If you put all the functions you would want in a shared object
>linked to with dlopen(), you might avoid fancy undocumented tricks
>with dlopen() and manage to stick to dlopen() the main program
>itself.
One could compile and link with -g, which will include the debugger
symbol table (the DWARF sections in the ELF executable). Then one
could open the executable with open("/proc/self/exe") (on linux,
slightly different on SVR4 or Solaris), and read and process the
dwarf information. Beware, it is a dense encoding and quite
complicated to decode.
If the symbols you need are in a shared object, you'll need to build that
with -g and open and read (again via /proc) the libraries then process
the DWARF sections.
A more traditional approach that I used when I wrote the linux kernel
debugger (KDB) was to post-process the executable (linux) with a script
which extracted the symbols (using nm) and created an additional C file
that mapped the symbol names and addresses; when compiled the output
gets linked into the executable.
-----[ Begin KSH script gensyms.ksh ]-------------------------------------
#!/bin/ksh -p
#
# Create an object section containing a symbol table.
#
# usage:
# gensyms.ksh elf generated-c-file
_elf=${1}
_tmpfile=${TMPDIR:-/tmp}/gensym.nm.$$
_ksym_c=${TMPDIR:-/tmp}/gensym.c1.$$
_ksym_d=${TMPDIR:-/tmp}/gensym.c2.$$
trap "rm -f ${_tmpfile} ${_ksym_c} ${_ksym_d} " EXIT HUP INT QUIT TERM
nm -n ${_elf} > ${_tmpfile}
echo "#include " > ${_ksym_c}
echo "#include " >> ${_ksym_c}
echo "struct _sym _syms[] __attribute__((section(\"symtab\"))) = {" >> ${_ksym_c}
echo "" > ${_ksym_d}
echo "const char _symstrings[] __attribute__((aligned(1),section(\"symstrings\"))) = " >> ${_ksym_d}
typeset -i _offset=0
while read _address _type _symbol
do
typeset -i _len
_len=$(echo -n "${_symbol}" | wc -c)
echo "{ 0x${_address}, ${_offset}, 0 }," >> ${_ksym_c}
echo " \"${_symbol}\\0\"" >> ${_ksym_d}
let _offset=_offset+_len+1
done < ${_tmpfile}
echo "};" >> ${_ksym_c}
echo ";" >> ${_ksym_d}
cat ${_ksym_c} ${_ksym_d} > ${2}
exit 0
--------[ End KSH Script ]------------------
For this, you compile and link twice. The first time to generate the
symbol table, the second to include the symbol table in the executable:
--------[ Begin Makefile Target ]-----------
$(EXE): exe_version buildit $(LIBRARIES) $(SUBDIRS)
_at_echo " PRELINK $_at_"
$(HUSHCOMPILE)ld -T build/exe.ld -o $(ELF) boot/$(OBJDIR)/setup64.o $(EXE_LIBRARIES) $(EXE_LIBRARIES) $(LIBGCC)
_at_echo " GENSYMS"
$(HUSHCOMPILE)tools/gensyms.ksh $(ELF) $(GENSYMC)
_at_echo " COMPILE $(GENSYMC)"
$(HUSHCOMPILE)cc -c $(CFLAGS) -o $(GENSYMO) $(GENSYMC)
_at_echo " LINK $_at_"
$(HUSHCOMPILE)ld -M -T build/exe.ld -o $(ELF) boot/$(OBJDIR)/setup64.o $(GENSYMO) $(EXE_LIBRARIES) $(EXE_LIBRARIES) $(LIBGCC) > $(EXEMAP)
-------[ End Makefile Target ]--------------
Add to your 'exe.ld' file for the linker:
-------[ Begin LD file fragment ]-----------
. = ALIGN(64);
_ssymtab = .;
symtab : {
*(symtab)
}
_esymtab = .;
_ssymstrings = .;
symstrings : {
*(symstrings)
}
_esymstrings = .;
-------[ End LD file fragment ]-------------
With this in your linker control file (along with the rest of
the control file contents), this will include the symbol table
in your executable the second time through: Four global symbols
are defined that are accessible to your program:
_ssymtab, _esymtab, _ssymstring, _esymstrings
-------[ debugger/symbols.h ]-----------------
struct _sym {
uint64 s_address; // Absolute symbol address
uint32 s_offset; // Offset in char _symstrings[] of symbol name
uint32 s_flags; // Flags
};
-------[ End debugger/symbols.h ]-------------
_ssymtab points to the start of an array of struct _sym entries for each
symbol. _esymtab points to the entry following the end of the array.
_ssymstrings points to the start of the symbol strings, _esymstrings
points to one entry past the symbol strings.
scott
Written by scott_at_slp53.sl.home (Scott Lurndal) 15/10/2011 23.33.57
Check some pics on this site!
23/05/2012 22.33.46