Use dlsym on a static binary - static-linking

Is there any hope of running dlopen(NULL, ...) and getting symbols for a statically compiled binary?
For example, with the following code I can get symbols if the program is compiled dynamically and I use -rdynamic.
$ gcc -o foo foo.c -ldl -rdynamic
$ ./foo bar
In bar!
But with -static I get a cryptic error message:
$ gcc -static -o foo foo.c -ldl -rdynamic
/tmp/cc5LSrI5.o: In function `main':
foo.c:(.text+0x3a): warning: Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
$ ./foo bar
/lib/x86_64-linux-gnu/: cannot read file data: Is a directory
The source for foo.c follows:
#include <dlfcn.h>
#include <stdio.h>
int foo() { printf("In foo!\n"); }
int bar() { printf("In bar!\n"); }
int main(int argc, char**argv)
{
void *handle;
handle = dlopen(NULL, RTLD_NOW|RTLD_GLOBAL);
if (handle == NULL) {
fprintf(stderr, "%s\n", dlerror());
return 1;
}
typedef void (*function)();
function f = (function) dlsym(handle, argv[1]);
if (f == NULL) {
fprintf(stderr, "%s\n", dlerror());
return 2;
}
f();
return 0;
}

Is there any hope of running dlopen(NULL, ...) and getting symbols for a statically compiled binary?
No.
On most UNIXes you can't even link with -static and -ldl at the same time. Using glibc you can, but the utility of doing so is very limited. Basically, this ability is present only to support /etc/nsswitch.conf, and nothing else.
There is also no point in doing the dynamic lookup you did.
If you are trying to allow one of foo, bar or baz be called depending on command line arguments, just put a table in, e.g.
struct { const char *fname, void (*fn)(void) } table[] =
{ {"foo", &foo}, {"bar", &bar}, ...};
for (int i = 0; i < ...; ++i)
if (strcmp(argv[1], table[i].fname) == 0)
// found the entry, call it
(*table[i].fn)();
If you are trying to "maybe" call foo if it is linked in, and do nothing otherwise, then use weak references:
extern void foo(void) __attribute((weak));
if (&foo != 0) {
// foo was linked in, call it
foo();
}

Related

How to use CStruct

I'm trying to return struct from shared library written in C. This is simple code, for testing of returning structure and simple int32, libstruct.c, compiled by gcc -shared -Wl,-soname,libstruct.so.1 -o libstruct.so.1 libstruct.c:
#include <stdint.h>
int32_t newint(int32_t arg) {
return arg;
}
struct MyStruct {
int32_t member;
};
struct MyStruct newstruct(int32_t arg) {
struct MyStruct myStruct;
myStruct.member = arg;
return(myStruct);
}
I can use this library with simple C program, usestruct.c, compiled by gcc -o usestruct usestruct.c ./libstruct.so.1:
#include <stdio.h>
#include <stdint.h>
struct MyStruct {
int32_t member;
};
extern struct MyStruct newstruct(int32_t);
extern int32_t newint(int32_t);
int main() {
printf("%d\n", newint(42));
struct MyStruct myStruct;
myStruct = newstruct(42);
printf("%d\n", myStruct.member);
return 0;
}
I can launch it with LD_LIBRARY_PATH=./ ./usestruct, and it works correctly, prints two values. Now, let's to write analogous program in raku, usestruct.raku:
#!/bin/env raku
use NativeCall;
sub newint(int32) returns int32 is native('./libstruct.so.1') { * }
say newint(42);
class MyStruct is repr('CStruct') {
has int32 $.member;
}
sub newstruct(int32) returns MyStruct is native('./libstruct.so.1') { * }
say newstruct(42).member;
This prints first 42, but then terminates with segmentation fault.
In C this example works, but I'm not expert in C, maybe I forgot something, some compile options? Or is this a bug of rakudo?
NativeCall interface requires that transaction of C structs be made with pointers:
CStruct objects are passed to native functions by reference and native functions must also return CStruct objects by reference.
Your C function, however, returns a new struct by value. Then, i guess, this is tried to be interpreted as a memory address as it expects a pointer, and tries to read/write from wild memory areas, hence the segfault.
You can pointerize your function as:
struct MyStruct* newstruct(int32_t val) {
/* dynamically allocating now */
struct MyStruct *stru = malloc(sizeof *stru);
stru->member = val;
return stru;
}
with #include <stdlib.h> at the very top for malloc. Raku program is essentially the same modulo some aesthetics:
# prog.raku
use NativeCall;
my constant LIB = "./libstruct.so";
class MyStruct is repr("CStruct") {
has int32 $.member;
}
# C bridge
sub newint(int32) returns int32 is native(LIB) { * }
sub newstruct(int32) returns MyStruct is native(LIB) { * }
say newint(42);
my $s := newstruct(84);
say $s;
say $s.member;
We build the lib & run the Raku program to get
$ gcc -Wall -Wextra -pedantic -shared -o libstruct.so -fPIC mod_struct.c
$ raku prog.raku
42
MyStruct.new(member => 84)
84
(took the liberty to rename C file to "mod_struct.c")
Seems good. But there's an issue: now that a dynamic allocation was made, responsibility to deliver it back arises. And we need to do it ourselves with a C-bridged freer:
When a CStruct-based type is used as the return type of a native function, the memory is not managed for you by the GC.
So
/* addendum to mod_struct.c */
void free_struct(struct MyStruct* s) {
free(s);
}
Noting that, since the struct itself didn't have dynamic allocations on its members (as it only has an integer), we didn't do further freeing.
Now the Raku program needs to be aware of this, and use it:
# prog.raku
use NativeCall;
my constant LIB = "./libstruct.so";
class MyStruct is repr("CStruct") {
has int32 $.member;
}
# C bridge
sub newint(int32) returns int32 is native(LIB) { * }
sub newstruct(int32) returns MyStruct is native(LIB) { * }
sub free_struct(MyStruct) is native(LIB) { * }; # <-- new!
say newint(42);
my $s := newstruct(84);
say $s;
say $s.member;
# ... after some time
free_struct($s);
say "successfully freed struct";
and the output follows as
42
MyStruct.new(member => 84)
84
successfully freed struct
Manually keeping track of MyStruct objects to remember freeing them after some time might be cumbersome; that would be writing C! In the Raku level, we already have a class representing the struct; then we can add a DESTROY submethod to it that frees itself whenever garbage collector deems necessary:
class MyStruct is repr("CStruct") {
has int32 $.member;
submethod DESTROY {
free_struct(self);
}
}
With this addition, no manual calls to free_struct is needed (in fact, better not because it might lead double freeing which is undefined behaviour on C level).
P.S. your main C file might be revisioned, e.g., a header file seems in order but that's out of scope or that was only a demonstrative example who knows. In either case, thanks for providing an MRE and welcome to the website.
In addition to great #Mustafa's answer.
I found another way to solve my problem: we can allocate structure in raku and pass it to C function. Here is an example, file mod_struct.c:
#include <stdint.h>
struct MyStruct {
int32_t member;
};
void writestruct(struct MyStruct *outputStruct, int32_t arg) {
outputStruct->member = arg;
}
File usestruct.raku:
#!/bin/env raku
use NativeCall;
class MyStruct is repr('CStruct') {
has int32 $.member;
}
sub writestruct(MyStruct is rw, int32) is native('./libstruct.so') { * }
my $myStruct = MyStruct.new;
writestruct($myStruct, 42);
say $myStruct.member;
Compile and run it:
$ gcc -Wall -Wextra -pedantic -shared -o libstruct.so -fPIC mod_struct.c
$ ./usestruct.raku
42

different symbols with the same name in ELF binary

Can a statically linked ELF file (with symbols) have two different symbols with same name?
Can a statically linked ELF file (with symbols) have two different symbols with same name?
Absolutely, provided the symbols have local linkage. Example:
// foo.c
static int foo1() { return 42; }
int foo() { return foo1(); }
// bar.c
static int foo1() { return 24; }
int main() { return foo1(); }
gcc -static foo.c bar.c
nm ./a.out | grep ' foo1'
0000000000401c2d t foo1
0000000000401c48 t foo1
QED.

Undeclared GTK_OBJECT during g++ compilation

I get errors during compilation of a GTK+ application saying I have undeclared functions/definitions (I believe GTK_OBJECT might be a definition in a header file). This is my code (main.c):
#include <gtk/gtk.h>
static gint delete_event_cb(GtkWidget* w, GdkEventAny* e, gpointer data);
int main(int argc, char *argv[]) {
//Create widgets
GtkWidget *window;
gtk_init(&argc, &argv);
//Initialize widgets
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
//Configure widgets
gtk_window_set_title(GTK_WINDOW(window), "Hello World");
//Display widgets
gtk_widget_show(window);
//Set up signals
gtk_signal_connect(GTK_OBJECT(window), "delete_event", GTK_SIGNAL_FUNC(delete_event_cb), NULL);
gtk_main();
return 0;
}
static gint delete_event_cb(GtkWidget* w, GdkEventAny* e, gpointer data) {
gtk_main_quit();
turn FALSE;
}
I am using the following command in bash:
g++ `pkg-config --libs --cflags gtk+-3.0` main.c -o binary
I do have the developer version of gtk+ 3.0 installed. Any help is greatly appreciated.
Edit: This is the error message I get:
main.c: In function ‘int main(int, char**)’:
main.c:21:41: error: ‘GTK_OBJECT’ was not declared in this scope
gtk_signal_connect(GTK_OBJECT(window), "delete_event", GTK_SIGNAL_FUNC(delete_event_cb), NULL);
^
main.c:21:91: error: ‘GTK_SIGNAL_FUNC’ was not declared in this scope
gtk_signal_connect(GTK_OBJECT(window), "delete_event", GTK_SIGNAL_FUNC(delete_event_cb), NULL);
^
main.c:21:98: error: ‘gtk_signal_connect’ was not declared in this scope
gtk_signal_connect(GTK_OBJECT(window), "delete_event", GTK_SIGNAL_FUNC(delete_event_cb), NULL);
^
In file included from /usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h:9:0,
from /usr/include/glib-2.0/glib/gtypes.h:32,
from /usr/include/glib-2.0/glib/galloca.h:32,
from /usr/include/glib-2.0/glib.h:30,
from /usr/include/gtk-3.0/gdk/gdkconfig.h:13,
from /usr/include/gtk-3.0/gdk/gdk.h:30,
from /usr/include/gtk-3.0/gtk/gtk.h:30,
from main.c:1:
main.c: In function ‘gint delete_event_cb(GtkWidget*, GdkEventAny*, gpointer)’:
/usr/include/glib-2.0/glib/gmacros.h:229:17: error: ‘turn’ was not declared in this scope
#define FALSE (0)
^
main.c:29:10: note: in expansion of macro ‘FALSE’
turn FALSE;
^
I solved it by myself, but it was difficult to find out how. I gave the wrong order of arguments to g++ and missed an argument as well. This is the bash command that worked for me:
g++ `pkg-config --libs --cflags gtk+-3.0` main.c -o binary `pkg-config --libs gtk+-3.0`

Googlemock - multiple actions in WillOnce cause build error

I am already using gtest for some time but recently wanted to try out gmock. I am trying to mock class with method that returns value but also returns something in output parameter through reference. Here is my small code.
#include <vector>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
using namespace ::testing;
class AReal
{
public:
virtual bool foo(std::vector<int>& v) const = 0;
};
class AMock : public AReal
{
public:
MOCK_CONST_METHOD1(foo, bool(std::vector<int>&));
};
class B
{
public:
B(AReal* _a) : a(_a) {}
bool foo(std::vector<int>& v) const { return a->foo(v); }
private:
AReal* a;
};
class FooTest : public Test {};
TEST_F(FooTest,
DummyTestVector) {
AMock a;
B b(&a);
std::vector<int> exp = { 1, 2, 3 };
EXPECT_CALL(a, foo(_))
.Times(1)
.WillOnce(AllOf(SetArgReferee<0>(exp), Return(true)));
std::vector<int> load;
EXPECT_TRUE(a.foo(load));
EXPECT_EQ(exp, load);
}
int main(int argc, char** argv) {
::testing::InitGoogleMock(&argc, argv);
return RUN_ALL_TESTS();
}
However, this code gives me this error.
$ g++ -Wall -Wextra -std=c++14 -I. -o test test.cpp gmock-gtest-all.cc -lpthread
test.cpp: In member function ‘virtual void FooTest_DummyTestVector_Test::TestBody()’:
test.cpp:40:61: error: no matching function for call to ‘testing::internal::TypedExpectation<bool(std::vector<int>&)>::WillOnce(testing::internal::AllOfResult2<testing::SetArgRefereeActionP<0, std::vector<int> >, testing::internal::ReturnAction<bool> >::type)’
.WillOnce(AllOf(SetArgReferee<0>(exp), Return(true)));
^
In file included from test.cpp:2:0:
gmock/gmock.h:10172:21: note: candidate: testing::internal::TypedExpectation<F>& testing::internal::TypedExpectation<F>::WillOnce(const testing::Action<F>&) [with F = bool(std::vector<int>&)]
TypedExpectation& WillOnce(const Action<F>& action) {
^
gmock/gmock.h:10172:21: note: no known conversion for argument 1 from ‘testing::internal::AllOfResult2<testing::SetArgRefereeActionP<0, std::vector<int> >, testing::internal::ReturnAction<bool> >::type {aka testing::internal::BothOfMatcher<testing::SetArgRefereeActionP<0, std::vector<int> >, testing::internal::ReturnAction<bool> >}’ to ‘const testing::Action<bool(std::vector<int>&)>&’
If I don't use AllOf but rather specify just one action, either SetArgReferee or Return, everything works just fine. The use of AllOf causes this kind of error. I have found about AllOf here gmock multiple in-out parameters SetArgReferee and basically my code is same as the answer.
After one whole afternoon of trying everything I found out it was just my stupidity. All the time I somehow thought that AllOf == DoAll. Realized it just now.

ignoring return value of ‘int scanf(const char*, ...)’, declared with attribute warn_unused_result [-Wunused-result]?

When I compiled the following program like:
g++ -O2 -s -static 2.cpp it gave me the warning ignoring return value of ‘int scanf(const char*, ...)’, declared with attribute warn_unused_result [-Wunused-result].
But when I remove -02 from copiling statement no warning is shown.
My 2.cpp program:
#include<stdio.h>
int main()
{
int a,b;
scanf("%d%d",&a,&b);
printf("%d\n",a+b);
return 0;
}
What is the meaning of this warning and what is the meaning of -O2 ??
It means that you do not check the return value of scanf.
It might very well return 1 (only a is set) or 0 (neither a nor b is set).
The reason that it is not shown when compiled without optimization is that the analytics needed to see this is not done unless optimization is enabled. -O2 enables the optimizations - http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html.
Simply checking the return value will remove the warning and make the program behave in a predicable way if it does not receive two numbers:
if( scanf( "%d%d", &a, &b ) != 2 )
{
// do something, like..
fprintf( stderr, "Expected at least two numbers as input\n");
exit(1);
}
I took care of the warning by making an if statement that matches the number of arguments:
#include <iostream>
#include <cstdio>
using namespace std;
int main() {
int i;
long l;
long long ll;
char ch;
float f;
double d;
//6 arguments expected
if(scanf("%d %ld %lld %c %f %lf", &i, &l, &ll, &ch, &f, &d) == 6)
{
printf("%d\n", i);
printf("%ld\n", l);
printf("%lld\n", ll);
printf("%c\n", ch);
printf("%f\n", f);
printf("%lf\n", d);
}
return 0;
}