I have a 3rd party C static library that uses xdr_wrapstring. I am moving to RH 8 where these symbols are not unavailable in the default /lib64/libc.so.6, but are available as versioned symbols (xdr_wrapstring#GLIBC_2.2.5)? Is there a way to tell the linker to resolve xdr_wrapstring to xdr_wrapstring#GLIBC_2.2.5?
I can't link with libtirpc (which provides unversioned symbols) due to it requiring libssl.so & libcrypto.so via libk5crypto.so
Prefaced by the top comments ...
The assembler .symver shows some promise. A web search on it shows:
http://web.mit.edu/rhel-doc/3/rhel-as-en-3/symver.html
https://man7.org/conf/lca2006/shared_libraries/slide19a.html
Linking against older symbol version in a .so file
From this, I've created a symver.s file that has stubs that seems to work on my system [which has the same versioned symbols issue].
However, I'd have a look at those linked pages (e.g.) symver is also an attribute, so it may be possible to do this with inline asm from a .c file.
I've created a crude test program:
// xdrtest.c -- print address of xdr_wrapstring
#include <stdio.h>
void xdr_wrapstring(void);
int
main(void)
{
void *ptr = xdr_wrapstring;
printf("%p\n",ptr);
return 0;
}
Here is an better test program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#define ALEN 1000
#define sysfault(_fmt...) \
do { \
fprintf(stderr,_fmt); \
exit(1); \
} while (0)
XDR xdrs;
void
sendstring(const char *str)
{
static char buf[ALEN];
char *bp;
strcpy(buf,str);
bp = buf;
if (! xdr_wrapstring(&xdrs,&bp))
sysfault("sendstring: xdr_wrapstring fail -- str='%s' buf='%s'\n",
str,buf);
}
void
recvstring(const char *str)
{
static char buf[ALEN];
char *bp;
bp = buf;
if (! xdr_wrapstring(&xdrs,&bp))
sysfault("recvstring: xdr_wrapstring fail -- str='%s' buf='%s'\n",
str,buf);
fprintf(stderr,"buf=%p bp=%p str='%s' bp='%s'\n",buf,bp,str,bp);
if (strcmp(bp,str) != 0)
sysfault("recvstring: MISMATCH\n");
}
void
writer(void)
{
xdrstdio_create(&xdrs, stdout, XDR_ENCODE);
sendstring("hello");
sendstring("world");
sendstring("goodbye");
sendstring("galaxy");
}
void
reader(void)
{
xdrstdio_create(&xdrs, stdin, XDR_DECODE);
recvstring("hello");
recvstring("world");
recvstring("goodbye");
recvstring("galaxy");
}
int
main(int argc,char **argv)
{
int opt_dir = -1;
--argc;
++argv;
for (; argc > 0; --argc, ++argv) {
char *cp = *argv;
if (*cp != '-')
break;
cp += 2;
switch (cp[-1]) {
case 'r':
opt_dir = 0;
break;
case 'w':
opt_dir = 1;
break;
}
}
switch (opt_dir) {
case 0:
reader();
break;
case 1:
writer();
break;
default:
sysfault("main: -r/-w not specified\n");
break;
}
return 0;
}
Here is the "magic" xdrver.s file:
.globl xdrstdio_create
.symver foo, xdrstdio_create#GLIBC_2.2.5
xdrstdio_create:
jmp foo
.globl xdr_wrapstring
.symver bar, xdr_wrapstring#GLIBC_2.2.5
xdr_wrapstring:
jmp bar
Compile with (e.g.):
cc -o xdrtest xdrtest.c xdrver.s
Or, of course, we can create xdrver.o and link with whatever program we want.
Anyway, to test the program:
./xdrtest -w | ./xdrtest -r
And, the output is:
buf=0x4044a0 bp=0x4044a0 str='hello' bp='hello'
buf=0x4044a0 bp=0x4044a0 str='world' bp='world'
buf=0x4044a0 bp=0x4044a0 str='goodbye' bp='goodbye'
buf=0x4044a0 bp=0x4044a0 str='galaxy' bp='galaxy'
I try to import some C-function that generates an array in SystemVerilog.
Here is code:
#include "svdpi.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void getPacket(int packetSize, svOpenArrayHandle fpSig, svOpenArrayHandle err)
{
int* cfpSig = (int*) calloc(packetSize, sizeof(int));
double* cerr = (double*)calloc(packetSize, sizeof(double));
for(int i = 0; i < packetSize; ++i)
{
cfpSig[i] = i;
cerr[i] = 1.1*i;
printf("%d %f\n",cfpSig[i],cerr[i]);
}
printf("----------");
memcpy((int*) svGetArrayPtr(fpSig),cfpSig,packetSize);
memcpy((int*) svGetArrayPtr(err),cerr,packetSize);
free(cfpSig);
free(cerr);
}
import "DPI-C" function void getPacket(input int packetSize,
output int fpSig[], output real err[]);
module top();
initial begin
parameter int packetSize = 4;
int fpSig[packetSize];
real err[packetSize];
getPacket(packetSize,fpSig,err);
for(int i = 0; i < packetSize; ++i) begin
$display("fpSig: %d\nerr : %f",fpSig[i],err[i]);
end
end
endmodule
But when I compile the c-code manually, an error is generated at the linking stage: undefined reference to 'svGetArrayPtr'.
I have not previously worked with svOpenArrayHandle and it was enough to connect the header file "svdpi.h". I tried to look for some svdpi.dll lib in the questa install folder, but didn't find it.
If I compile c-file by vlog it's working fine, but I want to compile it manually because I plan to include matlab libs and compiling via vlog will become uncomfortable.
In Questasim simulator, the library containing the svGetArrayPtr symbol is mtipli.dll
This question is something of a trick C question or a trick clang/gcc question. I'm not sure which.
I phrased it like I did because the final array is in main.c, but the structs that are in the array are defined in C modules.
The end goal of what I am trying to do is to be able to define structs in seperate C modules and then have those structs be available in a contiguous array right from program start. I do not want to use any dynamic code to declare the array and put in the elements.
I would like it all done at compile or link time -- not at run time.
I'm looking to end up with a monolithic blob of memory that gets setup right from program start.
For the sake of the Stack Overflow question, I thought it would make sense if I imagined these as "drivers" (like in the Linux kernel) Going with that...
Each module is a driver. Because the team is complex, I do not know how many drivers there will ultimately be.
Requirements:
Loaded into contiguous memory (an array)
Loaded into memory at program start
installed by the compiler/linker, not dynamic code
a driver exists because source code exists for it (no dynamic code to load them up)
Avoid cluttering up the code
Here is a contrived example:
// myapp.h
//////////////////////////
struct state
{
int16_t data[10];
};
struct driver
{
char name[255];
int16_t (*on_do_stuff) (struct state *state);
/* other stuff snipped out */
};
// drivera.c
//////////////////////////
#include "myapp.h"
static int16_t _on_do_stuff(struct state *state)
{
/* do stuff */
}
static const struct driver _driver = {
.name = "drivera",
.on_do_stuff = _on_do_stuff
};
// driverb.c
//////////////////////////
#include "myapp.h"
static int16_t _on_do_stuff(struct state *state)
{
/* do stuff */
}
static const struct driver _driver = {
.name = "driverb",
.on_do_stuff = _on_do_stuff
};
// driverc.c
//////////////////////////
#include "myapp.h"
static int16_t _on_do_stuff(struct state *state)
{
/* do stuff */
}
static const struct driver _driver = {
.name = "driverc",
.on_do_stuff = _on_do_stuff
};
// main.c
//////////////////////////
#include <stdio.h>
static struct driver the_drivers[] = {
{drivera somehow},
{driverb somehow},
{driverc somehow},
{0}
};
int main(void)
{
struct state state;
struct driver *current = the_drivers;
while (current != 0)
{
printf("we are up to %s\n", current->name);
current->on_do_stuff(&state);
current += sizeof(struct driver);
}
return 0;
}
This doesn't work exactly.
Ideas:
On the module-level structs, I could remove the static const keywords, but I'm not sure how to get them into the array at compile time
I could move all of the module-level structs to main.c, but then I would need to remove the static keyword from all of the on_do_stuff functions, and thereby clutter up the namespace.
In the Linux kernel, they somehow define kernel modules in separate files and then through linker magic, they are able to be loaded into monolithics
Use a dedicated ELF section to "collect" the data structures.
For example, define your data structure in info.h as
#ifndef INFO_H
#define INFO_H
#ifndef INFO_ALIGNMENT
#if defined(__LP64__)
#define INFO_ALIGNMENT 16
#else
#define INFO_ALIGNMENT 8
#endif
#endif
struct info {
long key;
long val;
} __attribute__((__aligned__(INFO_ALIGNMENT)));
#define INFO_NAME(counter) INFO_CAT(info_, counter)
#define INFO_CAT(a, b) INFO_DUMMY() a ## b
#define INFO_DUMMY()
#define DEFINE_INFO(data...) \
static struct info INFO_NAME(__COUNTER__) \
__attribute__((__used__, __section__("info"))) \
= { data }
#endif /* INFO_H */
The INFO_ALIGNMENT macro is the alignment used by the linker to place each symbol, separately, to the info section. It is important that the C compiler agrees, as otherwise the section contents cannot be treated as an array. (You'll obtain an incorrect number of structures, and only the first one (plus every N'th) will be correct, the rest of the structures garbled. Essentially, the C compiler and the linker disagreed on the size of each structure in the section "array".)
Note that you can add preprocessor macros to fine-tune the INFO_ALIGNMENT for each of the architectures you use, but you can also override it for example in your Makefile, at compile time. (For GCC, supply -DINFO_ALIGNMENT=32 for example.)
The used attribute ensures that the definition is emitted in the object file, even though it is not referenced otherwise in the same data file. The section("info") attribute puts the data into a special info section in the object file. The section name (info) is up to you.
Those are the critical parts, otherwise it is completely up to you how you define the macro, or whether you define it at all. Using the macro is easy, because one does not need to worry about using unique variable name for the structure. Also, if at least one member is specified, all others will be initialized to zero.
In the source files, you define the data objects as e.g.
#include "info.h"
/* Suggested, easy way */
DEFINE_INFO(.key = 5, .val = 42);
/* Alternative way, without relying on any macros */
static struct info foo __attribute__((__used__, __section__("info"))) = {
.key = 2,
.val = 1
};
The linker provides symbols __start_info and __stop_info, to obtain the structures in the info section. In your main.c, use for example
#include "info.h"
extern struct info __start_info[];
extern struct info __stop_info[];
#define NUM_INFO ((size_t)(__stop_info - __start_info))
#define INFO(i) ((__start_info) + (i))
so you can enumerate all info structures. For example,
int main(void)
{
size_t i;
printf("There are %zu info structures:\n", NUM_INFO);
for (i = 0; i < NUM_INFO; i++)
printf(" %zu. key=%ld, val=%ld\n", i,
__start_info[i].key, INFO(i)->val);
return EXIT_SUCCESS;
}
For illustration, I used both the __start_info[] array access (you can obviously #define SOMENAME __start_info if you want, just make sure you do not use SOMENAME elsewhere in main.c, so you can use SOMENAME[] as the array instead), as well as the INFO() macro.
Let's look at a practical example, an RPN calculator.
We use section ops to define the operations, using facilities defined in ops.h:
#ifndef OPS_H
#define OPS_H
#include <stdlib.h>
#include <errno.h>
#ifndef ALIGN_SECTION
#if defined(__LP64__) || defined(_LP64)
#define ALIGN_SECTION __attribute__((__aligned__(16)))
#elif defined(__ILP32__) || defined(_ILP32)
#define ALIGN_SECTION __attribute__((__aligned__(8)))
#else
#define ALIGN_SECTION
#endif
#endif
typedef struct {
size_t maxsize; /* Number of values allocated for */
size_t size; /* Number of values in stack */
double *value; /* Values, oldest first */
} stack;
#define STACK_INITIALIZER { 0, 0, NULL }
struct op {
const char *name; /* Operation name */
const char *desc; /* Description */
int (*func)(stack *); /* Implementation */
} ALIGN_SECTION;
#define OPS_NAME(counter) OPS_CAT(op_, counter, _struct)
#define OPS_CAT(a, b, c) OPS_DUMMY() a ## b ## c
#define OPS_DUMMY()
#define DEFINE_OP(name, func, desc) \
static struct op OPS_NAME(__COUNTER__) \
__attribute__((__used__, __section__("ops"))) = { name, desc, func }
static inline int stack_has(stack *st, const size_t num)
{
if (!st)
return EINVAL;
if (st->size < num)
return ENOENT;
return 0;
}
static inline int stack_pop(stack *st, double *to)
{
if (!st)
return EINVAL;
if (st->size < 1)
return ENOENT;
st->size--;
if (to)
*to = st->value[st->size];
return 0;
}
static inline int stack_push(stack *st, double val)
{
if (!st)
return EINVAL;
if (st->size >= st->maxsize) {
const size_t maxsize = (st->size | 127) + 129;
double *value;
value = realloc(st->value, maxsize * sizeof (double));
if (!value)
return ENOMEM;
st->maxsize = maxsize;
st->value = value;
}
st->value[st->size++] = val;
return 0;
}
#endif /* OPS_H */
The basic set of operations is defined in ops-basic.c:
#include "ops.h"
static int do_neg(stack *st)
{
double temp;
int retval;
retval = stack_pop(st, &temp);
if (retval)
return retval;
return stack_push(st, -temp);
}
static int do_add(stack *st)
{
int retval;
retval = stack_has(st, 2);
if (retval)
return retval;
st->value[st->size - 2] = st->value[st->size - 1] + st->value[st->size - 2];
st->size--;
return 0;
}
static int do_sub(stack *st)
{
int retval;
retval = stack_has(st, 2);
if (retval)
return retval;
st->value[st->size - 2] = st->value[st->size - 1] - st->value[st->size - 2];
st->size--;
return 0;
}
static int do_mul(stack *st)
{
int retval;
retval = stack_has(st, 2);
if (retval)
return retval;
st->value[st->size - 2] = st->value[st->size - 1] * st->value[st->size - 2];
st->size--;
return 0;
}
static int do_div(stack *st)
{
int retval;
retval = stack_has(st, 2);
if (retval)
return retval;
st->value[st->size - 2] = st->value[st->size - 1] / st->value[st->size - 2];
st->size--;
return 0;
}
DEFINE_OP("neg", do_neg, "Negate current operand");
DEFINE_OP("add", do_add, "Add current and previous operands");
DEFINE_OP("sub", do_sub, "Subtract previous operand from current one");
DEFINE_OP("mul", do_mul, "Multiply previous and current operands");
DEFINE_OP("div", do_div, "Divide current operand by the previous operand");
The calculator expects each value and operand to be a separate command-line argument for simplicity. Our main.c contains operation lookup, basic usage, value parsing, and printing the result (or error):
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include "ops.h"
extern struct op __start_ops[];
extern struct op __stop_ops[];
#define NUM_OPS ((size_t)(__stop_ops - __start_ops))
static int do_op(stack *st, const char *opname)
{
struct op *curr_op;
if (!st || !opname)
return EINVAL;
for (curr_op = __start_ops; curr_op < __stop_ops; curr_op++)
if (!strcmp(opname, curr_op->name))
break;
if (curr_op >= __stop_ops)
return ENOTSUP;
return curr_op->func(st);
}
static int usage(const char *argv0)
{
struct op *curr_op;
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv0);
fprintf(stderr, " %s RPN-EXPRESSION\n", argv0);
fprintf(stderr, "\n");
fprintf(stderr, "Where RPN-EXPRESSION is an expression using reverse\n");
fprintf(stderr, "Polish notation, and each argument is a separate value\n");
fprintf(stderr, "or operator. The following operators are supported:\n");
for (curr_op = __start_ops; curr_op < __stop_ops; curr_op++)
fprintf(stderr, "\t%-14s %s\n", curr_op->name, curr_op->desc);
fprintf(stderr, "\n");
return EXIT_SUCCESS;
}
int main(int argc, char *argv[])
{
stack all = STACK_INITIALIZER;
double val;
size_t i;
int arg, err;
char dummy;
if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
return usage(argv[0]);
for (arg = 1; arg < argc; arg++)
if (sscanf(argv[arg], " %lf %c", &val, &dummy) == 1) {
err = stack_push(&all, val);
if (err) {
fprintf(stderr, "Cannot push %s to stack: %s.\n", argv[arg], strerror(err));
return EXIT_FAILURE;
}
} else {
err = do_op(&all, argv[arg]);
if (err == ENOTSUP) {
fprintf(stderr, "%s: Operation not supported.\n", argv[arg]);
return EXIT_FAILURE;
} else
if (err) {
fprintf(stderr, "%s: Cannot perform operation: %s.\n", argv[arg], strerror(err));
return EXIT_FAILURE;
}
}
if (all.size < 1) {
fprintf(stderr, "No result.\n");
return EXIT_FAILURE;
} else
if (all.size > 1) {
fprintf(stderr, "Multiple results:\n");
for (i = 0; i < all.size; i++)
fprintf(stderr, " %.9f\n", all.value[i]);
return EXIT_FAILURE;
}
printf("%.9f\n", all.value[0]);
return EXIT_SUCCESS;
}
Note that if there were many operations, constructing a hash table to speed up the operation lookup would make a lot of sense.
Finally, we need a Makefile to tie it all together:
CC := gcc
CFLAGS := -Wall -O2 -std=c99
LDFLAGS := -lm
OPS := $(wildcard ops-*.c)
OPSOBJS := $(OPS:%.c=%.o)
PROGS := rpncalc
.PHONY: all clean
all: clean $(PROGS)
clean:
rm -f *.o $(PROGS)
%.o: %.c
$(CC) $(CFLAGS) -c $^
rpncalc: main.o $(OPSOBJS)
$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $#
Because this forum does not preserve Tabs, and make requires them for indentation, you probably need to fix the indentation after copy-pasting the above. I use sed -e 's|^ *|\t|' -i Makefile
If you compile (make clean all) and run (./rpncalc) the above, you'll see the usage information:
Usage: ./rpncalc [ -h | --help ]
./rpncalc RPN-EXPRESSION
Where RPN-EXPRESSION is an expression using reverse
Polish notation, and each argument is a separate value
or operator. The following operators are supported:
div Divide current operand by the previous operand
mul Multiply previous and current operands
sub Subtract previous operand from current one
add Add current and previous operands
neg Negate current operand
and if you run e.g. ./rpncalc 3.0 4.0 5.0 sub mul neg, you get the result 3.000000000.
Now, let's add some new operations, ops-sqrt.c:
#include <math.h>
#include "ops.h"
static int do_sqrt(stack *st)
{
double temp;
int retval;
retval = stack_pop(st, &temp);
if (retval)
return retval;
return stack_push(st, sqrt(temp));
}
DEFINE_OP("sqrt", do_sqrt, "Take the square root of the current operand");
Because the Makefile above compiles all C source files beginning with ops- in to the final binary, the only thing you need to do is recompile the source: make clean all. Running ./rpncalc now outputs
Usage: ./rpncalc [ -h | --help ]
./rpncalc RPN-EXPRESSION
Where RPN-EXPRESSION is an expression using reverse
Polish notation, and each argument is a separate value
or operator. The following operators are supported:
sqrt Take the square root of the current operand
div Divide current operand by the previous operand
mul Multiply previous and current operands
sub Subtract previous operand from current one
add Add current and previous operands
neg Negate current operand
and you have the new sqrt operator available.
Testing e.g. ./rpncalc 1 1 1 1 add add add sqrt yields 2.000000000, as expected.
I've got an library which must read data from sqlite database by calling
extern int read(char** argv, int argc); // from header
it must process:
int read(char** argv, int argc) {
char* lineborder1;
char* lineborder2;
char* spaces1;
char* spaces2;
int maxl2 = 0, maxl1 = 0;
int i, maxi1, maxi2;
if (prelude() == -1) return -1;
// etc...
where prelude is inner procedure for sqlite connection:
int prelude() {
timefile = 0;
f = NULL;
#ifndef WIN32
char* temp = (char*)calloc(200, sizeof(char));
#endif
queries = (char**)malloc(sizeof(char*) * q_cnt);
for (x = 0; x < q_cnt; x++) {
queries[x] = (char*)malloc(sizeof(char) * q_size);
}
#ifdef WIN32
retval = sqlite3_open("todo.db3", &handle);
#else
home = (char*)getenv("HOME");
strcpy(temp, home);
retval = sqlite3_open(strcat(temp, "/.todo.db3"), &handle);
free(temp);
#endif
if (retval) {
printf("Database connection failed\n\r");
return -1;
}
return 0;
}
whole source is here : bitbucket: ctodo.c
I call this read from my application:
else if ((strcmp(argv[1], "read") == 0) || (strcmp(argv[1], "r") == 0)) {
return read(argv, argc);
but getting infinity cycle of this read call:
>>./todo r
Database connection failed
Database connection failed
Database connection failed
.... etc
here is how do I build it:
gcc -I . -c -o todo.a ctodo.c -lsqlite3 -O3
gcc -I . -o todo cctodo.c -lsqlite3 -O3 todo.a
help or version calls wrok fine and read works fine on windows, something specific to my linux build is here but I can't find a bug so far. what could call this read to run in infinity cycle like that?
The read function is defined in libc.so, and used to, you know, read data.
It is exceedingly likely that sqlite3_open() calls it.
By introducing your own function called read(), you've made your program enter infinite loop. If you wait long enough, your program will run out of stack and crash.
Doctor, it hurts when I do that. Well, don't do that :-)
I have written a code where in it would take in a executable file and the [lib*.so] library as my arguments and link # Run-time.
I want to also take in the function in the (*.o) file # run-time and link it.
But I don't know how to go about it.
EDIT 1:
The function I'm trying to link is a part of the .o file in the lib*.so library.
So I want to specify the library name and also the function name which is in the same library # Run-Time.
For eg. If my library contains two functions(i.e *.o files) the linker should compile the function which I want to use #Run-Time.
I have posted the code,please help :
#include <stdio.h>
#include <unistd.h>
#include <dlfcn.h> // use -ldl
typedef float (*DepFn)(short, short);
int main(int argc, char* argv[])
{
void* lib;
DepFn df;
if(argc < 2)
return printf("USAGE: %s lib-file\n", argv[0]);
lib = dlopen(argv[1], RTLD_NOW);
if(lib == NULL)
return printf("ERROR: Cannot load library\n");
df = dlsym(lib, "Depreciation");
if(df)
{
short l, i;
printf("Enter useful-life of asset: ");
scanf("%hd", &l);
for(i = 1; i <= l; i++)
{
float d = 100 * df(l, i);
printf("%hd\t%.1f%%\n", i, d);
}
}
else
printf("ERROR: Invalid library\n");
dlclose(lib);
}
If you need to take the function name at runtime, you need to pass it in argv[2], and instead of hardcoding function-name in the dlsym use argv[2].
if(argc < 3)
return printf("USAGE: %s lib-file function-name\n", argv[0]);
lib = dlopen(argv[1], RTLD_NOW);
if(lib == NULL)
return printf("ERROR: Cannot load library\n");
df = dlsym(lib, argv[2]);
You cannot load a relocatable (*.o) at run time using standard functions. You need to make sure the object is compiled as position independent code (e.g. -fPIC) and then make a shared object out of it. Something like ld -shared -o foo.so foo.o may do the trick.
Based on your comments, you just want to link to your shared library,
change your code to:
extern float Depreciation(short i,k); //should rather go in a header file
int main(int argc, char* argv[])
{
short l, i;
printf("Enter useful-life of asset: ");
scanf("%hd", &l);
for(i = 1; i <= l; i++)
{
float d = 100 * Depreciation(l, i);
printf("%hd\t%.1f%%\n", i, d);
}
}
Compile and link to your shared library:
gcc -o myprogram myprogram.c -lXX
Your libXX.so would need to be installed in e.g. /usr/lib/ for the above to work
See here for more info.