Building and using shared libraries?

I would like to figure out how to build a shared library which can then
be used by some of my applications. As an instructive project, I’m doing
the following:

  1. Create a shared library, libShared.so that has a single function:

// Shared.c
void
Foo()
{
printf(“In the shared library!\n”);
}

  1. Create a program, which just calls into the shared library:

// Main.c
int
main()
{
printf(“Before foo\n”);
Foo();
printf(“After foo\n”);
return 1;
}

I can’t seem to get this to work. I build everything as follows:

Build the shared library

qcc -o Shared.o Shared.c
qcc -shared -o libShared.so Shared.o

Build the app, using the shared library

qcc -o Main.o Main.c
qcc -o Test Main.o libShared.so

When I run Test, I get a core dump. gdb is singularly uninformative –
I’m guessing that is dying way early in startup.

Can someone give me a push in the right direction. I’d really like to
get shared libraries working in my project.

Thanks in advance,
Eric

Build the shared library

qcc -o Shared.o Shared.c

you missed a -shared (or a -fpic for gcc heads) in the compile phase…

qcc -shared -o libShared.so Shared.o

If you want to be able to debug it, you should also pass -Wl,-soname=libShared.so
here.

Hope this helps.

Colin “really must write a few articles for the QDN” Burgess


cburgess@qnx.com

In article <90ppoh$435$2@nntp.qnx.com>, cburgess@qnx.com wrote:

Build the shared library

qcc -o Shared.o Shared.c

you missed a -shared (or a -fpic for gcc heads) in the compile phase…

Note to self: stop typing code into the newsreader from memory.

The actual script I was using to test the system had the following line:

qcc -c -o Shared.o Shared.c

However, this is still missing the -shared option. Amazingly, when I add
-shared to the compile line, the test works.

Just so I understand this: It is not sufficient to link the library by
using the -shared option. One must also compile the invididual files
using the -shared option. Important safety tip. Thanks!

By experiment, it seems that code which is destined for an app (i.e. NOT
a shared library) runs just fine if compiled with -shared. That is, if
the main app is built using the following:

qcc -shared -c -o Main.o Main.c
qcc -o Test Main.o libShared.so

Then Test runs just fine. Thus, I am tempted to put -shared into the
default flags with which I compile all .c files. This would allow me to
compile all my .c files without explicit regard for whether the result
will go into a .so or an app. What’s the downside of specifying -shared
for all compiles?

qcc -shared -o libShared.so Shared.o

If you want to be able to debug it, you should also pass
-Wl,-soname=libShared.so
here.

Yeah, debugging is probably important. We’ll have to add that, too.

Thanks!
Eric

Eric Berdahl <berdahl@intelligentparadigm.com> wrote:

Then Test runs just fine. Thus, I am tempted to put -shared into the
default flags with which I compile all .c files. This would allow me to
compile all my .c files without explicit regard for whether the result
will go into a .so or an app. What’s the downside of specifying -shared
for all compiles?

Look at the generated code… -shared is slower and fatter.


Brian Stecher (bstecher@qnx.com) QNX Software Systems, Ltd.
phone: +1 (613) 591-0931 (voice) 175 Terence Matthews Cr.
+1 (613) 591-3579 (fax) Kanata, Ontario, Canada K2M 1W8

Brian Stecher <bstecher@qnx.com> wrote:

Eric Berdahl <> berdahl@intelligentparadigm.com> > wrote:
Then Test runs just fine. Thus, I am tempted to put -shared into the
default flags with which I compile all .c files. This would allow me to
compile all my .c files without explicit regard for whether the result
will go into a .so or an app. What’s the downside of specifying -shared
for all compiles?

Look at the generated code… -shared is slower and fatter.

Yeah, what he said… ;v)


cburgess@qnx.com

In article <90rl6h$75d$3@nntp.qnx.com>, cburgess@qnx.com wrote:

Brian Stecher <> bstecher@qnx.com> > wrote:
Eric Berdahl <> berdahl@intelligentparadigm.com> > wrote:
Then Test runs just fine. Thus, I am tempted to put -shared into the
default flags with which I compile all .c files. This would allow me
to
compile all my .c files without explicit regard for whether the result
will go into a .so or an app. What’s the downside of specifying
-shared
for all compiles?

Look at the generated code… -shared is slower and fatter.

Yeah, what he said… ;v)

Fair enough, but my simple experiment suggests that the different isn’t
huge. Can you elaborate on which structures or elements are larger or
slower? Are we talking about an instruction here and there (which could
be important for highly embedded systems with limited RAM requirements)
or are we talking about a 20% size increase (which could be important
for everyone).

I imagine the analysis also depends on how much of my code is going to
end up in a shared library and how much will end up in a static app.

THe basic difference is that when you compile -shared, all calls
to functions are done indirectly via the PLT(procedure linkage table)
and the GOT(global offset table), and all global data references
are done through the GOT.

So if you code doesn’t use global variables, and doesn’t call a lot
of functions, then there won’t be too much of a difference.

Eric Berdahl <berdahl@intelligentparadigm.com> wrote:

In article <90rl6h$75d$> 3@nntp.qnx.com> >, > cburgess@qnx.com > wrote:

Brian Stecher <> bstecher@qnx.com> > wrote:
Eric Berdahl <> berdahl@intelligentparadigm.com> > wrote:
Then Test runs just fine. Thus, I am tempted to put -shared into the
default flags with which I compile all .c files. This would allow me
to
compile all my .c files without explicit regard for whether the result
will go into a .so or an app. What’s the downside of specifying
-shared
for all compiles?

Look at the generated code… -shared is slower and fatter.

Yeah, what he said… ;v)

Fair enough, but my simple experiment suggests that the different isn’t
huge. Can you elaborate on which structures or elements are larger or
slower? Are we talking about an instruction here and there (which could
be important for highly embedded systems with limited RAM requirements)
or are we talking about a 20% size increase (which could be important
for everyone).

I imagine the analysis also depends on how much of my code is going to
end up in a shared library and how much will end up in a static app.


cburgess@qnx.com

cburgess@qnx.com wrote:

THe basic difference is that when you compile -shared, all calls
to functions are done indirectly via the PLT(procedure linkage table)
and the GOT(global offset table), and all global data references
are done through the GOT.

So if you code doesn’t use global variables, and doesn’t call a lot
of functions, then there won’t be too much of a difference.

Correct me if I’m wrong, Colin, but this only applies to extern
variables and functions – statics don’t have this extra overhead, do
they?


Wojtek Lerch (wojtek@qnx.com) QNX Software Systems Ltd.

Wojtek Lerch <wojtek@qnx.com> wrote:

cburgess@qnx.com > wrote:
THe basic difference is that when you compile -shared, all calls
to functions are done indirectly via the PLT(procedure linkage table)
and the GOT(global offset table), and all global data references
are done through the GOT.

So if you code doesn’t use global variables, and doesn’t call a lot
of functions, then there won’t be too much of a difference.

Correct me if I’m wrong, Colin, but this only applies to extern
variables and functions – statics don’t have this extra overhead, do
they?

Sorry, but yup, they do.

Pretty much anything that isn’t an automatic variable must be
referred to via the GOT, since normally there would be a relocation
performed on the access.


cburgess@qnx.com

cburgess@qnx.com wrote:

Wojtek Lerch <> wojtek@qnx.com> > wrote:
cburgess@qnx.com > wrote:
THe basic difference is that when you compile -shared, all calls
to functions are done indirectly via the PLT(procedure linkage table)
and the GOT(global offset table), and all global data references
are done through the GOT.

So if you code doesn’t use global variables, and doesn’t call a lot
of functions, then there won’t be too much of a difference.

Correct me if I’m wrong, Colin, but this only applies to extern
variables and functions – statics don’t have this extra overhead, do
they?

Sorry, but yup, they do.

Pretty much anything that isn’t an automatic variable must be
referred to via the GOT, since normally there would be a relocation
performed on the access.

Hm… Doesn’t the CALL opcode on an x86 always use an offset from its
own address, rather than an absolute address that needs a relocation?

I thought the only reason for function calls to have to go through the
table is because for an extern function, the compiler must assume that
the function might be in another object; but for a static function, the
compiler should always be able to say “jump this many bytes from here”,
shouldn’t it?

Is GCC just being lazy?


Wojtek Lerch (wojtek@qnx.com) QNX Software Systems Ltd.

Wojtek Lerch <wojtek@qnx.com> wrote:

Correct me if I’m wrong, Colin, but this only applies to extern
variables and functions – statics don’t have this extra overhead, do
they?

Sorry, but yup, they do.

Pretty much anything that isn’t an automatic variable must be
referred to via the GOT, since normally there would be a relocation
performed on the access.

Hm… Doesn’t the CALL opcode on an x86 always use an offset from its
own address, rather than an absolute address that needs a relocation?

Ah, you meant static functions. Yes, they are called direct. On x86
at least.

I thought the only reason for function calls to have to go through the
table is because for an extern function, the compiler must assume that
the function might be in another object; but for a static function, the
compiler should always be able to say “jump this many bytes from here”,
shouldn’t it?

Is GCC just being lazy?


Wojtek Lerch (> wojtek@qnx.com> ) QNX Software Systems Ltd.


cburgess@qnx.com

cburgess@qnx.com a écrit :

Wojtek Lerch <> wojtek@qnx.com> > wrote:

Correct me if I’m wrong, Colin, but this only applies to extern
variables and functions – statics don’t have this extra overhead, do
they?

Sorry, but yup, they do.

Pretty much anything that isn’t an automatic variable must be
referred to via the GOT, since normally there would be a relocation
performed on the access.

Hm… Doesn’t the CALL opcode on an x86 always use an offset from its
own address, rather than an absolute address that needs a relocation?

Ah, you meant static functions. Yes, they are called direct. On x86
at least.

I thought the only reason for function calls to have to go through the
table is because for an extern function, the compiler must assume that
the function might be in another object; but for a static function, the
compiler should always be able to say “jump this many bytes from here”,
shouldn’t it?

Is GCC just being lazy?


Wojtek Lerch (> wojtek@qnx.com> ) QNX Software Systems Ltd.


cburgess@qnx.com

Is there a real reason for the linker to not be able to distinguish a near
function (inside some linked objects) and an external function (inside a
shared lib) an to adapt the CALL?

Alain.

Alain Bonnefoy <alain.bonnefoy@icbt.com> wrote:

Is there a real reason for the linker to not be able to distinguish a near
function (inside some linked objects) and an external function (inside a
shared lib) an to adapt the CALL?

If there was some way to tell the linker, then yes, you could do this. If
it’s internal to just the code module, then static will work.

The GNU linker doesn’t have this facility, unfortunately.


cburgess@qnx.com