ELF weak import / fallback stubs for glibc functions - linux

I am trying to make our program runnable on some old Linux versions. One common import that prevents it is __longjmp_chk, added in glibc 2.11 but missing in older ones. One "solution" is to use -D_FORTIFY_SOURCE=0 but this turns off other fortify functions (__printf_chk etc) which are present in the target libc. Is there a way to make __longjmp_chk a "weak import" which would use the function from libc.so.6 if present, and fall back to local stub if not?

Is there a way to make __longjmp_chk a "weak import" which would use
the function from libc.so.6 if present, and fall back to local stub
if not?
I'd say yes, using dlsym() to check for __longjmp_chk and acting accordingly:
/* cc -ldl */
#define _GNU_SOURCE
#include <setjmp.h>
#include <stdio.h>
#include <dlfcn.h>
void __longjmp_chk(sigjmp_buf env, int val)
{
void (*p)(sigjmp_buf, int) = dlsym(RTLD_NEXT, "__longjmp_chk");
if (p)
printf("use the function from libc\n"),
p(env, val);
else
{
printf("falling back to local stub\n");
/* local stub - whatever that may be */
}
}
main()
{ // try it
sigjmp_buf env;
while (!setjmp(env)) __longjmp_chk(env, 1);
return 0;
}

I am trying to make our program runnable on some old Linux versions.
There are only a few ways to make this work, and most of them are enumerated here.
Is there a way to make __longjmp_chk a "weak import".
No.

Related

How do i log errors while writing custom varnish module?

I am learning varnish and about extending the varnish vmod with inline c code. And I am starting it with writing my own custom varnish module. I want to log errors and failure from my custom module. How do i achieve that?
I have options to choose from various logging libraries available for C. But i want to check if there is any inbuilt varnish library to make use of it. Below is my sample code of a vmod c file.
#include "vrt.h"
#include "cache/cache.h"
#include "vcc_if.h"
#include <jansson.h>
#define JSON_ERROR "-1"
#define JSON_LOC "/etc/example.json"
VCL_STRING
vmod_validate_mymod(VRT_CTX) {
(void) ctx;
char *return_code = "0";
json_t *jobj;
json_error_t error;
jobj = json_load_file(JSON_LOC,0,&error);
if (!jobj) {
// error log here
return JSON_ERROR;
}
return return_code;
}
I want en error log line to be added in a cutom log file when the the if condition in the code above is true. Please help.
You want VSLb:
VSLb(ctx->vsl, SLT_VCL_Log, "%d", 5);
If you need to build larger string, or need allocations, use the WS_* functions, their allocations are freed at the end of the rquest automatically.
See how std.log() does it: https://github.com/varnishcache/varnish-cache/blob/389d7ba28e0d0e3a2d5c30a959aa517e5166b246/vmod/vmod_std.c#L145-L153

Running LLVM passes on Windows 10 gives no output in terminal?

I've the sample pass code from LLVM.org:
#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
namespace {
struct Hello : public FunctionPass {
static char ID;
Hello() : FunctionPass(ID) {}
bool runOnFunction(Function &F) override {
errs() << "Hello: ";
errs().write_escaped(F.getName()) << '\n';
return false;
}
}; // end of struct Hello
} // end of anonymous namespace
char Hello::ID = 0;
static RegisterPass<Hello> X("hello", "Hello World Pass",
false /* Only looks at CFG */,
false /* Analysis Pass */);
The project builds fine and creates a SkeletonPass.dll.
When I execute the command:
C:\Users\nlykkei\Projects\llvm-pass-tutorial\build>opt -load skeleton\Debug\SkeletonPass.dll -hello foo.bc
opt: Unknown command line argument '-hello'. Try: 'opt -help'
opt: Did you mean '-help'?
opt doesn't recognize -hello option, even thus everything works fine on Ubuntu 16.04.
In addition, if I execute:
clang -Xclang -load -Xclang skeleton\Debug\SkeletonPass.dll foo.bc
nothing is printed out on Visual Studio terminal (Native Tools Command Prompt x86). On Linux, the function names are printed nicely for the same bitcode file.
What can be the reason for my experience? I do exactly the same on Windows 10 as I do on Ubuntu, but very different results.
Plugins are special beasts on Windows, because the latter does not support proper dynamic linking, so, your pass simply does not register itself in the PassRegistry. So you'd either need to compile all the LLVM into .dll or link your pass statically into opt / clang.

Linux alternative to _NSGetExecutablePath?

Is it possible to side-step _NSGetExecutablePath on Ubuntu Linux in place of a non-Apple specific approach?
I am trying to compile the following code on Ubuntu: https://github.com/Bohdan-Khomtchouk/HeatmapGenerator/blob/master/HeatmapGenerator2_Macintosh_OSX.cxx
As per this prior question that I asked: fatal error: mach-o/dyld.h: No such file or directory, I decided to comment out line 52 and am wondering if there is a general cross-platform (non-Apple specific) way that I can rewrite the code block of line 567 (the _NSGetExecutablePath block) in a manner that is non-Apple specific.
Alen Stojanov's answer to Programmatically retrieving the absolute path of an OS X command-line app and also How do you determine the full path of the currently running executable in go? gave me some ideas on where to start but I want to make certain that I am on the right track here before I go about doing this.
Is there a way to modify _NSGetExecutablePath to be compatible with Ubuntu Linux?
Currently, I am experiencing the following compiler error:
HeatmapGenerator_Macintosh_OSX.cxx:568:13: error: use of undeclared identifier
'_NSGetExecutablePath'
if (_NSGetExecutablePath(path, &size) == 0)
Basic idea how to do it in a way that should be portable across POSIX systems:
#define _XOPEN_SOURCE 500
#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
static char *path;
const char *appPath(void)
{
return path;
}
static void cleanup()
{
free(path);
}
int main(int argc, char **argv)
{
path = realpath(argv[0], 0);
if (!path)
{
perror("realpath");
return 1;
}
atexit(&cleanup);
printf("App path: %s\n", appPath());
return 0;
}
You can define an own module for it, just pass it argv[0] and export the appPath() function from a header.
edit: replaced exported variable by accessor method

Qt5 and GLEW MX => glewInit fails

We are migrating our project from Qt 4.8 to 5.4. We use multiple contexts in multiple thread. We use GLEW MX for this purpose (We make the context we desire current then call glewInit() on a local instance of GLEWContextStruct).
I'm trying to change QGLWidget and QGLContext to QOpenGLWidget and QOpenGLContext but I ended up not being able to initialize glew anymore.
GLEW doesn't return an error but glGetError() does.
I did install Qt 5.4 64 with OpenGL version.
Here is the code reduced to a minimum :
#include <QtWidgets/QApplication>
#define GLEW_MX
#define GLEW_STATIC
#include <GL/glew.h>
#include <qopenglcontext.h>
#include <qwindow.h>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
bool errQt;
int errGlew;
GLenum errorGL;
QSurfaceFormat requestedFormat;
requestedFormat.setVersion(3, 3);
requestedFormat.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile);
//Creates the QGLWidget using the current context:
QWindow window;
window.setSurfaceType(QSurface::OpenGLSurface);
window.setFormat(requestedFormat);
window.create();
//Create context
QOpenGLContext context;
context.setFormat(requestedFormat);
errQt = context.create(); //true
//Bind context
context.makeCurrent(&window);
//Glew context creation
GLEWContext* pCtx = new GLEWContext; //All forwards undefined
//Release context
context.doneCurrent();
return 1;
}
Any suggestion ? Is GLEW alright with Qt5.4 ?
EDIT 1 :
It appears the problem is not Qt related. The GLEWContext created doesn't have any function forward defined (all function pointers are undefined). The code has been updated to help the reviewer not lose focus.
I use glewInit() with Qt 5.4 in my project, but I'm using QWindow as my base class, not QOpenGLWidget.
In my ctor I do this:
QRiftWindow::QRiftWindow() {
setSurfaceType(QSurface::OpenGLSurface);
QSurfaceFormat format;
format.setDepthBufferSize(16);
format.setStencilBufferSize(8);
format.setVersion(4, 3);
format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile);
setFormat(format);
m_context = new QOpenGLContext;
m_context->setFormat(format);
m_context->create();
...
I execute my OpenGL work on a separate thread. Once the thread has started I call an setup method on my class
m_context->makeCurrent(this);
glewExperimental = true;
glewInit();
glGetError();
I've previously done this exact same setup with OpenGL 3.3 and had no issues.
You should actually get a warning about that:
#warning qopenglfunctions.h is not compatible with GLEW, GLEW defines will be undefined
#warning To use GLEW with Qt, do not include or after glew.h
Your "qopenglcontext.h" includes . To answer your question, you can use Qt + GLEW, but u can't easily mix up Qt-opengl with GLEW.

Create a shared lib using another shared lib

I have a shared library "libwiston.so". I am using this to create another shared library called "libAnimation.so", which will be used by another project. Now, the second library "libAnimation.so" can't be used in test code correctly. So I doubt that the creation of the second lib "libAnimation.so" is right. The gcc command to create this lib is
g++ -g -shared -Wl,-soname,libwiston.so -o libAnimation.so $(objs) -lc".
Has someone come across this problem?
That looks like a weird link line - you are creating libAnimation.so, but its internal DT_SONAME name is libwiston.so.
I don't think that what you wanted to do. Don't you want to link libAnimation.so against libwiston.so (-lwiston)?
g++ -g -shared -o libAnimation.so $(objs) -lc -lwiston
I think it would be easier to wrap your build in automake/autoconf and rely on libtool to get the shared library creation correct.
I'll do a humble review on the process of creating shared libraries.
Let's begin by creating libwiston.so. First we implement the function we would like to export and then define it on a header so other programs knows how to call it.
/* file libwiston.cpp
* Implementation of hello_wiston(), called by libAnimation.so
*/
#include "libwiston.h"
#include <iostream>
int hello_wiston(std::string& msg)
{
std::cout << msg << std::endl;
return 0;
}
and:
/* file libwiston.h
* Exports hello_wiston() as a C symbol.
*/
#include <string>
extern "C" {
int hello_wiston(std::string& msg);
};
This code can be compiled with: g++ libwiston.cpp -o libwiston.so -shared
Now we implement the second shared library, named libAnimation.so that calls the function exported by the first library.
/* file libAnimation.cpp
* Implementation of call_wiston().
* This function is a simple wrapper around hello_wiston().
*/
#include "libAnimation.h"
#include "libwiston.h"
#include <iostream>
int call_wiston(std::string& param)
{
hello_wiston(param);
return 0;
}
and header:
/* file libAnimation.h
* Exports call_wiston() as a C symbol.
*/
#include <string>
extern "C" {
int call_wiston(std::string& param);
};
Compile it with: g++ libAnimation.cpp -o libAnimation.so -shared -L. -lwiston
Finally, we create a small application to test libAnimation.
/* file demo.cpp
* Implementation of the test application.
*/
#include "libAnimation.h"
int main()
{
std::string msg = "hello stackoverflow!";
call_wiston(msg);
}
And compile it with: g++ demo.cpp -o demo -L. -lAnimation
There's an interesting tool named nm that you can use to list the symbols exported by your shared library. Using these examples, you could execute the following commands to check for the symbols:
nm libAnimation.so | grep call_wiston
outputs:
00000634 t _GLOBAL__I_call_wiston
000005dc T call_wiston
and also:
nm libwiston.so | grep hello_wiston
outputs:
0000076c t _GLOBAL__I_hello_wiston
000006fc T hello_wiston

Resources