__xstat dynamic symbol resolving error on 64bit - c++

I am trying to dynamically load stat function using dlopen and dlsym.
Functions from stat family are wrapped in corresponding functions __xstat, __xstat64 itp.
Following sniped of code, compiles and works when compiled in 32bit mode (sys/stat.h is included to get stat structure for sake of example)
#include <iostream>
#include <dlfcn.h>
#include <sys/stat.h>
typedef int (*xstat_f) (int __ver, const char *__filename, struct stat *__stat_buf);
int main()
{
auto* h = dlopen("libc.so.6", RTLD_LAZY);
if(!h)
{
return 1; // invalid handle
}
auto f = (xstat_f)dlsym(h, "__xstat");
if(!f)
{
return 1; // invalid handle
}
struct stat s = {};
const auto r = f(3, "/tmp", &s);
if (r != 0)
{
perror("stat");
return errno;
}
return 0;
}
g++ main.cpp -o main -ldl -m32
Executable compiled without -m32 switch on 64bit machine returns EINVAL (Invalid argument).
What is the reason?
Also I've made a minimal test
#include <iostream>
#include <sys/stat.h>
int main(){
struct stat s;
const auto x = stat("/tmp", &s);
if(x != 0) return errno;
return 0;
}
and using objdump -T, on both executables, 32bits and 64bits, shows that stat is resolved as __xstat, so I am using correct symbol. Also I've tried combination of __xstat/__xstat64, struct stat/stat64, same result.

__xstat declarations follows:
int __xstat(int ver, const char *path, (struct stat *stat_buf))
in documentation parameter ver is described like, ver shall be 3 or the behavior of these functions is undefined, which is not entirely true, because in source code, definition of _STAT_VER_LINUX follows:
#ifndef __x86_64__
# define _STAT_VER_LINUX 3
#else
# define _STAT_VER_LINUX 1
#endif
That's why __xstat call on 64bits was failling, parameter ver should have been set to 1, and 3 on 32bits compilation.

Related

I'm getting undefined reference to `i2c_smbus_read_word_data and 'extern "C"' doesn't fix it

I'm getting the error undefined reference to i2c_smbus_read_word_data(int, unsigned char)`
I've tried wrapping a few of my libraries in extern "C" but I get the same error. I tried this after seeing this answer to a similar problem.
Regardless of whether I wrap some or all of these include #include <linux/i2c-dev.h>, #include <i2c/smbus.h>, #include <linux/i2c.h>, #include <sys/ioctl.h> statements I get the same error.
The error is i2c_read.cpp:(.text+0xf8): undefined reference to i2c_smbus_read_word_data(int, unsigned char)'
collect2: error: ld returned 1 exit status`
I am running my command $g++ i2c_read.cpp -li2c with -li2c as you can see.
extern "C" {
#include <linux/i2c-dev.h>
#include <i2c/smbus.h>
}
#include <linux/i2c.h>
#include <sys/ioctl.h>
#include <fcntl.h> /* For O_RDWR */
#include <unistd.h>
#include <iostream>
using namespace std;
int file;
int adapter_nr = 2;
char filename[20];
int main() {
cout << filename << 19 << "/dev/i2c-1" << adapter_nr;
file = open(filename, O_RDWR);
if (file < 0) {
exit(1);
}
int addr = 0x74;
if (ioctl(file, I2C_SLAVE, addr) < 0) {
exit(1);
}
__u8 reg = 0x40;
__s32 res;
char buf[10];
res = i2c_smbus_read_word_data(file, reg);
if (res < 0) {
/* ERROR HANDLING: i2c transaction failed */
} else {
/* res contains the read word */
}
buf[0] = reg;
buf[1] = 0x42;
buf[2] = 0x43;
if (write(file, buf, 3) != 3) {
/* ERROR HANDLING: i2c transaction failed */
}
}
I did a sudo apt-get update and the problem went away.
I also ran a few commands to update the compiler, though it still says my g++ version is 7.5, so that might have also contributed.

compilation terminated fatal error: abc.h: No such file or directory

The project is all about handshaking Cpp with java For that i am using JNI, I made all the necesaary configuration make Cpp project generate header in src folder of Cpp project create ABC.h file and abc.Cpp file. when i bulid the abc.cpp file it shows error compilation failed due to p.thread no such directory found, if i remove this P.thread header file it shows ABC.h not found while ABC.h file is in same folder and we include on our Cpp file
please help me out how to fix this problem ,i am newbie in JNI
below attached PNG file show you the detail
ERROR ON ECLIPSE CONSOLE//////////////////////////////////////////
00:31:21 **** Incremental Build of configuration Default for project SyntacJNI ****
Info: Internal Builder is used for build
g++ "-IC:\\Program Files\\Java\\jdk1.7.0_21\\include\\win32" "-IC:\\Program Files\\Java\\jdk1.7.0_21\\include" -O2 -g -Wall -c -fmessage-length=0 -o "src\\abc
.o" "..\\src\\abc.cpp"
..\src\abc.cpp:10:21: fatal error:abc.h: No such file or directory
#include <pthread.h>
^
compilation terminated.
00:31:21 Build Finished (took 189ms)
///////////////////////////abc.cpp//////////////CODE Snippet////////////////////////
#include <fstream>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <windows.h>
#include <SyntacInterface.h>
#include <org_syntec_ivb_jni_DeviceCommunicationController.h>
using namespace std;
// An unsigned char can store 1 Bytes (8bits) of data (0-255)
typedef unsigned char BYTE;
// Global Var
bool gLive_View = true;
// Get the size of a file
#include <stdlib.h>
ULONG RcvdBytes;
volatile bool keepRunning = false;
volatile bool modeFlag = true;
static HANDLE hThread = NULL;
int compstr = 0xFF000F00;
long int count = 0;
static void run();
static void end();
static DWORD WINAPI ThreadProc(LPVOID lpParam);
static ULONG BuffSizeLive = 81408;
//CRITICAL_SECTION critical;
int got = 0;
static void run() {
DWORD dummy;
hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, &dummy);
}
static void end() {
keepRunning = false;
CloseHandle(hThread);
}
bool fexists(const char *filename) {
ifstream ifile(filename);
return ifile.good();
}
static DWORD WINAPI ThreadProc(LPVOID lpParam) {
while (keepRunning) {
BuffSizeLive = 327680;
UCHAR* Buff = (UCHAR*) malloc(sizeof(UCHAR) * BuffSizeLive);
ULONG RcvdBytes;
RcvdBytes = abc_GetCapture(Buff, BuffSizeLive);
if (RcvdBytes == 327680 || RcvdBytes == 81408) {
Syntac_WriteToBinaryFile(Buff,
"C:/listenDir/Capture_Mod1.BIN", RcvdBytes);
}
free(Buff);
cout << "got the frame stream " << got;
}
return 0;
}][1]

Field '__jmpbuf' could not be resolved -cpp

I get this error when trying to compile my program:
Field '__jmpbuf' could not be resolved
I looked for a solution for hours and can't seem to find out where is the culprit.
The Thread.h file contains the header of the class. It has the private member:
sigjmp_buf _env;
And the implementation is inside Thread.cpp:
#include "Thread.h"
#include <setjmp.h>
#include "translateAdd.h"
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/time.h>
#define COUNTER_INIT -1
int Thread::_idCounter = COUNTER_INIT;
Thread::Thread(void (*threadsFunc)(void))
: threadsFunction(threadsFunc), _stack(new char[STACK_SIZE]), _quantums(1)
{
address_t sp, pc;
sp = (address_t)_stack + STACK_SIZE - sizeof(address_t);
pc = (address_t)threadsFunc;
// set environment for later return
sigsetjmp(_env, 1);
(_env->__jmpbuf)[JB_SP] = translate_address(sp);
(_env->__jmpbuf)[JB_PC] = translate_address(pc);
sigemptyset(&_env->__saved_mask);
_id = ++_idCounter;
_state = READY;
}
EDIT: Using eclipse as the IDE under ubuntu 32bit
EDIT: Another complete example that doesn't compile on my machine:
#include <stdio.h>
#include <setjmp.h>
#include <signal.h>
#include <unistd.h>
#include <sys/time.h>
#define SECOND 1000000
#define STACK_SIZE 4096
char stack1[STACK_SIZE];
char stack2[STACK_SIZE];
sigjmp_buf env[2];
#ifdef __x86_64__
/* code for 64 bit Intel arch */
typedef unsigned long address_t;
#define JB_SP 6
#define JB_PC 7
/* A translation is required when using an address of a variable.
Use this as a black box in your code. */
address_t translate_address(address_t addr)
{
address_t ret;
asm volatile("xor %%fs:0x30,%0\n"
"rol $0x11,%0\n"
: "=g" (ret)
: "0" (addr));
return ret;
}
#else
/* code for 32 bit Intel arch */
typedef unsigned int address_t;
#define JB_SP 4
#define JB_PC 5
/* A translation is required when using an address of a variable.
Use this as a black box in your code. */
address_t translate_address(address_t addr)
{
address_t ret;
asm volatile("xor %%gs:0x18,%0\n"
"rol $0x9,%0\n"
: "=g" (ret)
: "0" (addr));
return ret;
}
#endif
void switchThreads(void)
{
static int currentThread = 0;
int ret_val = sigsetjmp(env[currentThread],1);
printf("SWITCH: ret_val=%d\n", ret_val);
if (ret_val == 1) {
return;
}
currentThread = 1 - currentThread;
siglongjmp(env[currentThread],1);
}
void f(void)
{
int i = 0;
while(1){
++i;
printf("in f (%d)\n",i);
if (i % 3 == 0) {
printf("f: switching\n");
switchThreads();
}
usleep(SECOND);
}
}
void g(void)
{
int i = 0;
while(1){
++i;
printf("in g (%d)\n",i);
if (i % 5 == 0) {
printf("g: switching\n");
switchThreads();
}
usleep(SECOND);
}
}
void setup(void)
{
address_t sp, pc;
sp = (address_t)stack1 + STACK_SIZE - sizeof(address_t);
pc = (address_t)f;
sigsetjmp(env[0], 1);
(env[0]->__jmpbuf)[JB_SP] = translate_address(sp);
(env[0]->__jmpbuf)[JB_PC] = translate_address(pc);
sigemptyset(&env[0]->__saved_mask);
sp = (address_t)stack2 + STACK_SIZE - sizeof(address_t);
pc = (address_t)g;
sigsetjmp(env[1], 1);
(env[1]->__jmpbuf)[JB_SP] = translate_address(sp);
(env[1]->__jmpbuf)[JB_PC] = translate_address(pc);
sigemptyset(&env[1]->__saved_mask);
}
int main(void)
{
setup();
siglongjmp(env[0], 1);
return 0;
}
If you really need to use the internal fields (which will only be valid for your compiler on your system) you need to check the types:
typedef struct __jmp_buf_tag sigjmp_buf[1];
That means that sigjmp_buf is not a pointer, but an array with a single structure in it. So you use it like a normal array of structures:
sigjmp_buf _env;
_env[0].__jmpbuf[x] = y;
I really recommend against the use the internal field of this structure. Linux have other functions to simplify cooperative threading (which is what you seem to be implementing).

Mounting an ISO with sys/mount.h

I'm trying to mount an ISO file in a C++ program in linux
I'm aware of the linux command to achieve this, i.e mount -o loop ~/Test.iso /mnt/myISO
But the mount(2) man page states the following prototype for mounting :
int mount(const char *source, const char *target,
const char *filesystemtype, unsigned long mountflags,
const void *data);
How do I specify the loop option here ?
--
Also, is it good (/acceptable) practice in general, in linux programming to use system shell calls from C++ to achieve tasks such as these ?
small example
#include <sys/mount.h>
#include <linux/loop.h>
#include <fcntl.h>
int main()
{
int file_fd, device_fd;
file_fd = open("./TVM_TOMI1.iso", O_RDWR);
if (file_fd < -1) {
perror("open backing file failed");
return 1;
}
device_fd = open("/dev/loop0", O_RDWR);
if (device_fd < -1) {
perror("open loop device failed");
close(file_fd);
return 1;
}
if (ioctl(device_fd, LOOP_SET_FD, file_fd) < 0) {
perror("ioctl LOOP_SET_FD failed");
close(file_fd);
close(device_fd);
return 1;
}
close(file_fd);
close(device_fd);
mount("/dev/loop0","/mnt/iso","iso9660",MS_RDONLY,"");
}
upd:
after unmount you need free loop:
device_fd = open("/dev/loop0", O_RDWR);
...
if (ioctl(device_fd, LOOP_CLR_FD, 0) < 0) {
perror("ioctl LOOP_CLR_FD failed");
return 1;
}
Here is a code, that also creates loop device for you. Be aware not to use such code in production, as there is no single check on return values, exceptions etc :).
#include <sys/mount.h> //mount
#include <sys/ioctl.h> //ioctl
#include <sys/stat.h> //open
#include <linux/loop.h> //LOOP_SET_FD
#include <fcntl.h> //open
#include <cstdio> // declaration of ::fileno
#include <cstdint> //int32_t
#include <sstream> //std::stringstream
#include <string>
constexpr char IMAGE_NAME[] = "image.iso"; //of course we need this file to be present in same folder as built tool
constexpr char MOUNT_POINT[] = "/tmp/image_mnt"; //of course we need this folder already created
constexpr char FILESYSTEM_TYPE[] = "iso9660";
constexpr char DEV_LOOP_CONTROL[] = "/dev/loop-control";
constexpr char DEV_LOOP_PREFIX[] = "/dev/loop";
constexpr int32_t MOUNT_FLAGS = MS_RDONLY;
int main()
{
const auto loop_control = std::fopen(DEV_LOOP_CONTROL, "r");
const auto loop_control_fd = fileno(loop_control);
const auto devnr = ioctl(loop_control_fd, LOOP_CTL_GET_FREE);
std::stringstream loopname;
loopname << DEV_LOOP_PREFIX << devnr;
const auto loop_device_name = loopname.str();
const auto loop_device = std::fopen(loop_device_name.c_str(), "r");
const auto loop_device_fd = fileno(loop_device);
const auto image = std::fopen(IMAGE_NAME, "r");
const auto image_fd = fileno(image);
//Associate the loop device with the open file whose file descriptor is passed as the (third) ioctl(2) argument.
ioctl(loop_device_fd, LOOP_SET_FD, image_fd);
const auto result = mount(loop_device_name.c_str(), MOUNT_POINT, FILESYSTEM_TYPE, MOUNT_FLAGS, NULL);
ioctl(loop_device_fd, LOOP_CLR_FD, 0);
return result;
}
based on:
http://man7.org/linux/man-pages/man4/loop.4.html
https://linux.die.net/man/2/mount

Challenges in writing wrappers for C++ functions so that they can be used from C code

I am now writing wrappers for C++ functions, such that they can be used from C code.
The idea is to compile the cpp files using g++ and the c files using gcc, then link them together (!), but exposing ONLY those functions that are needed, to the C programs, by making them available in a header file 'test.h' (or maybe test.hpp?), like so:
(Note how I do not expose function 'vector Tokenize(const string& str,const string& delimiters)')
test.h:
/* Header can be read by both C+ and C compilers, just the way we want! */
#ifndef TEST_H
#define TEST_H
#ifdef __cplusplus
extern "C" {
#endif
#if defined(__STDC__) || defined(__cplusplus)
extern int TokenizeC(const char* text, const char* delim, char ***output); /* ANSI C prototypes */
extern void reclaim2D(char ***store, unsigned int itemCount);
#endif
#ifdef __cplusplus
}
#endif
#endif /* TEST_H */
test.cpp:
#include <string>
#include <iostream>
#include <vector>
#include <assert.h>
#include "test.h"
using namespace std;
vector<string> Tokenize(const string& str,const string& delimiters)
{
vector<string> tokens;
string::size_type delimPos = 0, tokenPos = 0, pos = 0;
if(str.length() < 1) return tokens;
while(1)
{
delimPos = str.find_first_of(delimiters, pos);
tokenPos = str.find_first_not_of(delimiters, pos);
if(string::npos != delimPos)
{
if(string::npos != tokenPos)
{
if(tokenPos < delimPos) tokens.push_back(str.substr(pos,delimPos-pos));
else tokens.push_back("");
}
else tokens.push_back("");
pos = delimPos + 1;
}
else
{
if(string::npos != tokenPos) tokens.push_back(str.substr(pos));
else tokens.push_back("");
break;
}
}
return tokens;
}
int TokenizeC(const char* text, const char* delim, char ***output)
{
if((*output) != NULL) return -1; /* I will allocate my own storage, and no one tells me how much. Free using reclaim2D */
vector<string> s = Tokenize(text, delim);
// There will always be a trailing element, that will be blank as we keep a trailing delimiter (correcting this issue would not be worth the time, so this is a quick workaround)
assert(s.back().length() == 0); // This will be nop'ed in release build
s.pop_back();
(*output) = (char **)malloc(s.size() * sizeof(char *));
for(vector <string>::size_type x = 0; x < s.size(); x++)
{
(*output)[x] = strdup(s[x].c_str());
if(NULL == (*output)[x])
{
// Woops! Undo all
// TODO : HOW to test this scenario?
for(--x; x >= 0; --x)
{
free((*output)[x]);
(*output)[x] = NULL;
}
return -2;
}
}
return x; /* Return the number of tokens if sucessful */
}
void reclaim2D(char ***store, unsigned int itemCount)
{
for (int x = 0; itemCount < itemCount; ++x)
{
free((*store)[x]);
(*store)[x] = NULL;
}
free((*store));
(*store) = NULL;
}
poc.c:
#include <stdio.h>
#include "test.h"
int main()
{
const char *text = "-2--4--6-7-8-9-10-11-", *delim = "-";
char **output = NULL;
int c = TokenizeC(text, delim, &output);
printf("[*]%d\n", c);
for (int x = 0; x < c; ++x)
{
printf("[*]%s\n", output[x]);
}
reclaim2D(&output, c);
return 0;
}
Do you notice something wrong?
For starters, when I ran this program, I got "Unsatisfied code symbol '__gxx_personality_v0'"
Thankfully, there is something here : What is __gxx_personality_v0 for?
Once I ran g++ with options " -fno-exceptions -fno-rtti", the output now fails with "Unsatisfied data symbol '_ZNSs4_Rep20_S_empty_rep_storageE'"
Ofcourse, the two environments (the one to compile - HP-UX B.11.23 ia64 and the one to run the binary on - HP-UX B.11.31 ia64) have different library versions (but same architecture), and this should not be a reason for the errors.
I would also like to test out the case marked by "// TODO : HOW to test this scenario?", but that can wait for now.
Any pointers?
The easiest way to avoid undefined symbols while linking is to link with g++ (not gcc). You can still compile your .c file with gcc, though.
Also please use system at a time. The link error may go away if you run all your gcc and g++ commands on the same system (no matter the old or the new one).
To call a C++ function from C, you can't have mangled names. Remove the conditional test for __cplusplus where you do the extern "C". Even though your functions will be compiled by a C++ compiler, using extern "C" will cause it to avoid name-mangling.
Here is an example:
The C file.
/* a.c */
#include "test.h"
void call_cpp(void)
{
cpp_func();
}
int main(void)
{
call_cpp();
return 0;
}
The header file.
/* test.h */
#ifndef TEST_H
#define TEST_H
extern "C" void cpp_func(void);
#endif
The CPP file.
// test.cpp
#include <iostream>
#include "test.h"
extern "C" void cpp_func(void)
{
std::cout << "cpp_func" << std::endl;
}
The compiler command line.
g++ a.c test.cpp
Is there a reason why you haven't considered modifying Swig to do just this? I seem to remember that there is a developmental branch of Swig to do just this...