From: gerth@watson.ibm.com (John Gerth)
Subject: Re: Help with nlist(), XCOFF, and memory architecture...
Summary:  repost article 6210 with sample code
Date: Sun, 16 Aug 1992 17:38:11 GMT
Disclaimer: This posting represents the poster's views, not necessarily those of IBM
Organization: IBM T.J. Watson Research Center
Keywords: nlist dynamic load

Here's a recent bit of sample code (below ===CUT HERE===) which claims
to illustrate how to do the run-time resolution you are looking for.
I haven't actually run it yet myself (it's still too far down the priority
list) so caveat emptor.         

--
John Gerth	 gerth@watson.ibm.com		(914) 784-7639
--------------------- referenced article --------------------------
Article: 6210 of comp.unix.aix
From: pgainer@vnet.ibm.com (Patrick Gainer)
Date: Wed, 29 Jul 92 08:00:02 EDT
Newsgroups: comp.unix.aix
Subject: Re: more dynamic loading problems...
Organization: IBM - Toronto Lab
Disclaimer: This posting represents the poster's views, not those of IBM
News-Software: UReply 3.0

In <45808@shamash.cdc.com> Paul Dokas x4629 writes:
>I thought that I had solved my problems with dynamic loading, but things
>still aren't working properly.  It seems that when I create a dynamically
>loadable module, that the value returned by nlist() is not always the
>correct offset to the begining of the routine.  The included code for
>example creates a dynamically loadable module with 2 functions 'a_function()'
>and 'b_function()'.  Using nm, I find that the symbol 'a_function' has
>a value of 0x54.  But if I use dbx to look at the location pointed to by
>fn_ptr, I find that the value of 'a_function' should really be 0x18!

Also, I have posted this from a VM system (gasp) and the left and right
square brackets may be corrupted (I can't tell from here but it has happened
before).

================================CUT HERE====================================
/*=========================================================================*/
/*                                                                         */
/* DESCRIPTION:  A quick and dirty prototype of runtime loading and        */
/*               binding.                                                  */
/*                                                                         */
/*                                                                         */
/* Usage: cc -g -o dyload dyload.c  = builds this executable               */
/*        ld -T512 -H512 -e entry_point -lc -o object_file object_file.o   */
/*                                                                         */
/*=========================================================================*/

#include <stdio.h>
#include <nlist.h>
#include <malloc.h>


/* Type definitions */
typedef struct function_t
{
  char                  name[128];       /* function name */
  int                   (*code)();       /* function pointer */
  int                   arr[3];          /* 12 bytes for func descriptor */
} Function;

typedef struct nlist n_list;


/* Function prototype */
int
  load_and_bind(Function   *flist, char   *file);


main(int   argc, char   **argv)
{
  char                  *libpath="/u/patrick/tools/dyload:.";
  int                   result;
  int                   loop_control=1;
  char                  file_name[128];
  char                  func_name[128];
  Function              flist[2];

  /* optional arg for object file name */
  if (argc < 2)
  {
    printf("Enter name of object file to be loaded.\n");
    result = fgets(file_name, 128, stdin);

    /* remove carriage return from file name */
    file_name[strlen(file_name)-1] = 0x00;
  }
  else
  {
    strcpy(file_name,argv[1]);
  }

  /* load object module, resolve entry point information */
  flist[0].code = load(file_name,0,libpath);
  if (!flist[0].code)
  {
    printf("load call failed. Exiting.\n");
    exit(-1);
  }

  do       /* until user quits by setting loop_control == 0 */
  {
    /* get function to execute from user, preface name by a '.' */
    printf("Enter name of function you wish to execute.\n");
    flist[1].name[0] = '.';
    result = fgets(&(flist[1].name[1]), 128, stdin);

    /* remove carriage return from file name (added by fgets) */
    flist[1].name[strlen(flist[1].name)-1] = 0x00;

    /* hardcode function entry point - bad programming practise */
    strcpy(flist[0].name,".ibm_start");

    /* resolve function name and generate a function pointer */
    result = load_and_bind(flist,file_name);
    if (result != 0)
    {
      printf("function name resolving failed. Exiting.\n");
      exit(-2);
    }

    /* execute function */
    (flist[1].code)("Test input string",17);

    printf("Continue? (Yes == 1)\n");
    fflush(stdin);
    scanf("%d",&loop_control);
    fflush(stdin);

  } while (loop_control);

}



/*
 * Given a function name (string), this routine generates a function
 * descriptor and a function pointer to that descriptor. All addresses
 * are resolved so that the function pointer can be directly executed
 * by the calling procedure.
 *
 * Parameters:
 *  flist - contains two entries. The first holds the name of the entry
 *          point for the entire module. This is used to calculate a base
 *          address for the function to be resolved. The second contains
 *          the name of the function to be resolved.
 *  file  - contains the name of the object module containing the functions.
 */
int
  load_and_bind(Function   *flist, char   *file)
{
  int           i;
  n_list        *nlptr;
  int           result;


  /*===================================================================*/
  /* allocate array of 3 nlist structure - 1 for object module header, */
  /* 1 for function we wish to find, and 1 to NULL terminate array.    */
  /*===================================================================*/
  nlptr = (n_list *) calloc(3,sizeof(n_list));
  if (!nlptr)
  {
    return(-3);
  }

  /* set nlist name field for object module entry point */
  nlptr[0]._n._n_name = flist[0].name;

  /* set nlist name field for function name to be resolved */
  nlptr[1]._n._n_name = flist[1].name;

  /* set nlist name field terminator (NULL name) */
  nlptr[2]._n._n_name = "";

  /* call nlist to get function offsets from a name list */
  result = nlist(file, nlptr);
  if (result == -1)
  {
    perror("nlist");
    return(-4);
  }

  /*=========================================================================*/
  /* Here is where the addresses are resolved. Basically, the nlist call      */
  /* returns with the offsets from the entry point for each function. The     */
  /* entry point address was obtained via the load() call in main.            */
  /*                                                                          */
  /* Each function is associated with something called a function descriptor. */
  /* This structure (12 bytes) contains the function's virtual address in     */
  /* bytes 0 to 3 and the Table Of Contents address for the module in bytes   */
  /* 4-7. Bytes 8-11 are not used. A function pointer is just a pointer to    */
  /* this structure. To resolve a function's runtime address, The TOC entry   */
  /* from the entry point is used (since the TOC is the same for all funcs    */
  /* in a module) but the virtual address must be calculated. The entry_point */
  /* offset (obtained from nlist) is subtracted from the function-to-be-      */
  /* resolved's virtual address. This gives a base address. Then, the         */
  /* function-to-be-resolved's nlist offset is added to this base address to  */
  /* get the function's virtual address. Finally, the function pointer is set */
  /* to point to the function descriptor structure just created.              */
  /*==========================================================================*/

  /* copy entry point function descriptor to func-to-be-resolved's descriptor */
  memcpy(flist[1].arr,flist[0].code,12);

  /* set function pointer to point to newly obtained function descriptor */
  flist[1].code = (int(*)()) flist[1].arr;

  /*==============================================================*/
  /* Subtract the nlist offset for the module from the ptr value  */
  /* in flist[1].arr[0-3]. This will yield a base virtual address.*/
  /*==============================================================*/
  *((int *)flist[1].arr) = *((int *) flist[1].arr) - nlptr[0].n_value;

  /*==============================================================*/
  /* Add the nlist offset for this particular symbol to the base  */
  /* virtual address.                                             */
  /*==============================================================*/
  *((int *)flist[1].arr) = *((int *) flist[1].arr) + nlptr[1].n_value;

  /* done - free memory and return */
  free(nlptr);
  return(0);
}
-- 
John Gerth	 gerth@watson.ibm.com		(914) 784-7639
Newsgroups: comp.unix.aix