Tag Archives: NoteToMyself

Quiztime II

So, following up from the last quiztime which was about the importance of explicit linking, another case from the wonderful world of shared libraries.

This time we study the implications of dlopen, its parameters and C++. Consider the program and module below. If you run that, it will crash somewhat obscurely in libstdc++. Why?

#0  0x00007f687b2eb126 in std::ostream::sentry::sentry(std::ostream&) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#1  0x00007f687b2eb889 in std::basic_ostream >& std::__ostream_insert >(std::basic_ostream >&, char const*, long) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#2  0x00007f687b2ebd57 in std::basic_ostream >& std::operator< <  >(std::basic_ostream >&, char const*) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#3  0x00007f687a6f01a0 in Impl::print (this=0x558a9bc1f2e0, str="Hello") at module.cc:24
#4  0x0000558a99de3d1b in main (argc=1, argv=0x7ffca28cf538) at main.cc:31
#ifndef INTERFACE_H
#define INTERFACE_H
 
#include <string>
 
class IInterface {
    public:
        virtual ~IInterface() {};
        virtual void print(const std::string& str) = 0;
};
 
#endif // INTERFACE_H
</string>
#include "interface.h"
 
#include <iostream>
 
class Impl : public IInterface {
    public:
        Impl();
        virtual ~Impl();
        void print(const std::string& str);
};
 
extern "C" {
void *entry_point(void)
{
    return new Impl;
}
};
 
Impl::Impl() {};
Impl::~Impl() {};
 
void Impl::print(const std::string& str)
{
    std::cerr < <"Some text to print\n";
    std::cerr << "Got passed this: " << str << "\n";
    std::cerr << "=====\n";
}
#include <dlfcn .h>
#include <iostream>
 
#include "interface.h"
 
extern "C" {
typedef void *(*EntryFunction)(void);
};
 
int main(int argc, char *argv[])
{
    IInterface *iface;
    EntryFunction f;
 
    void *lib = dlopen("./module.so", RTLD_NOW | RTLD_DEEPBIND);
    if (lib == nullptr) {
        std::cerr < < dlerror () << "\n";
        return 1;
    }
 
    f = (EntryFunction) dlsym (lib, "entry_point");
 
    if (f == nullptr) {
        std::cerr << dlerror () << "\n";
        return 1;
    }
 
    iface = reinterpret_cast<IInterface *>(f());
 
    while (true) {
        iface->print ("Hello");
    }
}
</iostream></dlfcn>
.PHONY: all clean
all: main module.so
 
clean:
	rm -f main
	rm -f module.so
 
main: main.cc
	g++ -g -o $@ $< -ldl
 
module.so: module.cc
	g++ -g -o $@ -shared $< -fPIC

Quiztime!

Say you have a shared library with versioned symbols that has the function init(int *param) defined in two versions, where new_init is made the default for init (that’s what the  @@ means):

#include "shared1.h"
 
void new_init (int *param)
{
    *param = 0;
}
 
void old_init (int *param)
{
    *param = -1;
}
 
__asm__(".symver new_init,init@@VERS_2");
__asm__(".symver old_init,init@VERS_1");

Say you have a second shared library that provides a function do_something() uses that init from the first shared library:

#include "shared1.h"
 
int do_something ()
{
    int var;
    init (&var);
 
    return var;
}

And you have an app that just prints the result:

#include "shared2.h"
 
#include <stdio .h>
 
int main(int argc, char *argv[])
{
    printf ("Result: %d\n", do_something ());
 
    return 0;
}</stdio>

And all of this is cobbled together with the following Makefile:

all: app
 
libshared.so: shared1.c shared1.h
    cc -o $@ $< -shared -fPIC -Wl,--version-script=version.script
 
libmoreshared.so: libshared.so shared2.c
    cc -o $@ shared2.c -shared -fPIC
 
app: libmoreshared.so app.c
    cc -o $@ -L. app.c -lmoreshared -lshared

What’s the output of

LD_LIBRARY_PATH=. ./app

Update: Try to answer it without compiling and running it at first.
Update2: I forgot the version.script, sorry.

VERS_1 {
    local:
        old_init;
};
 
VERS_2 {
    local:
        new_init;
} VERS_1;

Resolving DBus uniqe names

Often you stumble across DBus logs (e.g. originating from bustle or dbus-monitor) which only feature DBus unique names (those :1.xyz numbers) and you can only guess which process it originates from.

Helper script to resolve those addresses to processes (if the system is still running):

#!/bin/bash
 
name=$1
while [ -n "$name" ]
do
    result=`LANG=C dbus-send \
                  --session \
                  --print-reply \
                  --dest=org.freedesktop.DBus \
                  / \
                  org.freedesktop.DBus.GetConnectionUnixProcessID \
                  string:"$name" 2>/dev/null`
    if [ $? -eq 0 ]
    then
        process=`ps ax | grep ^${result##* }`
        echo "$name -> $process"
    fi
    shift; name=$1
done

Fake rpm database in ubuntu

At work I’m currently developing software which is supposed to run on openSUSE. I need to query the package database at some point which of course does not exist on my ubuntu machine. Here’s a quick setup how to create a fake local RPM database:

echo "%_dbpath /home/user/rpmdb" >> ~/.rpmmacros
mkdir /home/user/rpmdb
rpm -i --nodeps --justdb --force-debian *.rpm

And that’s it.

any to WMV

While trying to vamp up XBox 360 support for rygel, I also need a transcoder suitable for the XBox. While H.264 would work it is CPU consuming and hard to get right for the XBox, because it is quite picky. So I decided to go for WMV1/WMA2. Prototype gst-launch commandline:

gst-launch filesrc location=input_file ! decodebin2 name=decoder \
               asfmux name=mux ! filesink location=foo.wmv \
               { decoder. ! queue ! ffenc_wmv1 bitrate=1200 ! mux. } \
               { decoder. ! queue ! audioconvert ! audioresample ! ffenc_wmav2 bitrate=64000 ! mux. }

I know that the curly braces are not needed anymore but I still think they improve readability a lot.
Update:The resulting file works great for offline playback on the XBox, but live streaming does not work unfortunatly. I had to rely on ffmux_asf to make live transcoding working.