How can I choose function behavior at compile time? - c

I have 4 files in the following example ; a header, a default implementation file, and 2 platform-specific implementation files.I define two functions; get_value_1 and get_value_2. The 'default' behavior is to return -1, but some of these functions have special implementations. I would like each function to return -1 only if another file didn't implement it.
/* interface.h *
***************/
int get_value_1();
int get_value_2();
/* default.c *
*************/
#include "interface.h"
#ifndef GET_VALUE_1
int get_value_1() { return -1; }
#endif
#ifndef GET_VALUE_2
int get_value_2() { return -1; }
#endif
/* platform1.c *
***************/
#include "interface.h"
#ifndef GET_VALUE_1
#define GET_VALUE_1
int get_value_1() { return 1; }
#endif
/* platform2.c *
***************/
#include "interface.h"
#ifndef GET_VALUE_2
#define GET_VALUE_2
int get_value_2() { return 2; }
#endif
But when I run the command gcc default.c platform1.c -shared -fpic -o platform1.so, it tells me that I've multiply defined the get_value_1 function, and that it was originally defined in platform1.c.
So how can I have a set of functions where a subset of those functions can have their behavior chosen at compile time?

make them weak in the default.c and "normal" in your platform files. So if the platform.c file implements this function as not weak, the weak one dfrom default.c will be replaced link time.
It is not the part of the standard but most compilers support it (it can be pragma, attribute or something else - you need to check in the compiler documentation)
gcc version:
#define __weak __attribute__((weak))
/* interface.h *
***************/
int get_value_1();
int get_value_2();
/* default.c *
*************/
#include "interface.h"
#ifndef GET_VALUE_1
__weak int get_value_1() { return -1; }
#endif
#ifndef GET_VALUE_2
__weak int get_value_2() { return -1; }
#endif
/* platform1.c *
***************/
#include "interface.h"
#ifndef GET_VALUE_1
#define GET_VALUE_1
int get_value_1() { return 1; }
#endif
/* platform2.c *
***************/
#include "interface.h"
#ifndef GET_VALUE_2
#define GET_VALUE_2
int get_value_2() { return 2; }
#endif

Related

Xcode duplicate symbol '_main'

I have a bunch of .O files that I generated from a makefile.u which compiles some .C files. I put all of the .O files into my Xcode project and I receive the below error when it builds:
duplicate symbol '_main' in:
/Users/.../Objects-normal/arm64/AppDelegate.o
/Users/.../LIBF2C/main.o
ld: 1 duplicate symbol for architecture arm64
I think I am bit confused because the main.o file is needed for my library, but the error seems to be telling me that I cannot have _main declared twice. So is there a solution for this, am I supposed to rename something to get it to build or any other ideas for how this can get resolved?
For some added context, this is specifically for the f2c libraries. So main.c(->main.o) from libf2c is:
/* STARTUP PROCEDURE FOR UNIX FORTRAN PROGRAMS */
#include "stdio.h"
#include "signal1.h"
#ifndef SIGIOT
#ifdef SIGABRT
#define SIGIOT SIGABRT
#endif
#endif
#ifndef KR_headers
#undef VOID
#include "stdlib.h"
#ifdef __cplusplus
extern "C" {
#endif
#endif
#ifndef VOID
#define VOID void
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifdef NO__STDC
#define ONEXIT onexit
extern VOID f_exit();
#else
#ifndef KR_headers
extern void f_exit(void);
#ifndef NO_ONEXIT
#define ONEXIT atexit
extern int atexit(void (*)(void));
#endif
#else
#ifndef NO_ONEXIT
#define ONEXIT onexit
extern VOID f_exit();
#endif
#endif
#endif
#ifdef KR_headers
extern VOID f_init(), sig_die();
extern int MAIN__();
#define Int /* int */
#else
extern void f_init(void), sig_die(const char*, int);
extern int MAIN__(void);
#define Int int
#endif
static VOID sigfdie(Sigarg)
{
Use_Sigarg;
sig_die("Floating Exception", 1);
}
static VOID sigidie(Sigarg)
{
Use_Sigarg;
sig_die("IOT Trap", 1);
}
#ifdef SIGQUIT
static VOID sigqdie(Sigarg)
{
Use_Sigarg;
sig_die("Quit signal", 1);
}
#endif
static VOID sigindie(Sigarg)
{
Use_Sigarg;
sig_die("Interrupt", 0);
}
static VOID sigtdie(Sigarg)
{
Use_Sigarg;
sig_die("Killed", 0);
}
#ifdef SIGTRAP
static VOID sigtrdie(Sigarg)
{
Use_Sigarg;
sig_die("Trace trap", 1);
}
#endif
int xargc;
char **xargv;
#ifdef __cplusplus
}
#endif
int
#ifdef KR_headers
main(argc, argv) int argc; char **argv;
#else
main(int argc, char **argv)
#endif
{
xargc = argc;
xargv = argv;
signal1(SIGFPE, sigfdie); /* ignore underflow, enable overflow */
#ifdef SIGIOT
signal1(SIGIOT, sigidie);
#endif
#ifdef SIGTRAP
signal1(SIGTRAP, sigtrdie);
#endif
#ifdef SIGQUIT
if(signal1(SIGQUIT,sigqdie) == SIG_IGN)
signal1(SIGQUIT, SIG_IGN);
#endif
if(signal1(SIGINT, sigindie) == SIG_IGN)
signal1(SIGINT, SIG_IGN);
signal1(SIGTERM,sigtdie);
#ifdef pdp11
ldfps(01200); /* detect overflow as an exception */
#endif
f_init();
#ifndef NO_ONEXIT
ONEXIT(f_exit);
#endif
MAIN__();
#ifdef NO_ONEXIT
f_exit();
#endif
exit(0); /* exit(0) rather than return(0) to bypass Cray bug */
return 0; /* For compilers that complain of missing return values; */
/* others will complain that this is unreachable code. */
}
#ifdef __cplusplus
}
#endif

Why can't I access uname struct's domainname member even if I defined _GNU_SOURCE

I am trying to some get Linux kernel version information by calling uname system call, but I am getting a compiler error saying ‘struct utsname’ has no member named ‘domainname’
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/utsname.h>
#define _GNU_SOURCE
int main(void) {
struct utsname buffer;
errno = 0;
if (uname(&buffer) != 0) {
perror("uname");
exit(EXIT_FAILURE);
}
printf("system name = %s\n", buffer.sysname);
printf("node name = %s\n", buffer.nodename);
printf("release = %s\n", buffer.release);
printf("version = %s\n", buffer.version);
printf("machine = %s\n", buffer.machine);
#ifdef _GNU_SOURCE
printf("domain name = %s\n", buffer.domainname);
#endif
return EXIT_SUCCESS;
}
according to https://linux.die.net/man/2/uname struct utsname is
struct utsname {
char sysname[]; /* Operating system name (e.g., "Linux") */
char nodename[]; /* Name within "some implementation-defined
network" */
char release[]; /* Operating system release (e.g., "2.6.28") */
char version[]; /* Operating system version */
char machine[]; /* Hardware identifier */
#ifdef _GNU_SOURCE
char domainname[]; /* NIS or YP domain name */
#endif
};
I am not sure what I missed here
From man feature_test_macros:
NOTE: In order to be effective, a feature test macro must be defined
before including any header files
It's:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/utsname.h>

Compilation error using rest and rime together in Cooja

I am trying to create a ContikiOS firmware that acts as a gateway using Rime and REST. The gateway must communicate to other motes with the Rime mesh, and can communicate to the outside via a REST API.
The following code is a combination from two default Contiki examples (rest-example/rest-server-example.c and rime/example-mesh.c). Therefore I include "rest.h", "net/rime.h", "net/rime/mesh.h".
The problem is when I try to compile this firmware using following makefile, the rime files don't get included into obj_sky and any Rime functions I use in the firmware get an 'undefined reference' error. However when I remove the lines in the makefile and any code referring to REST in the firmware code, it does compile (and adds the rime files to obj_sky).
Would anyone have an idea why rime does not get added after adding the rest-http app and what I can do to have it compile?
Thank you
Code
Compiler info
> make gateway.sky TARGET=sky
CC gateway.c
CC ../../platform/sky/./contiki-sky-main.c
LD gateway.sky
/usr/lib/gcc/msp430/4.6.3/../../../../msp430/bin/ld: gateway.sky section `.data' will not fit in region `rom'
/usr/lib/gcc/msp430/4.6.3/../../../../msp430/bin/ld: section .vectors loaded at [000000000000ffe0,000000000000ffff] overlaps section .data loaded at [000000000000ff0c,0000000000010037]
/usr/lib/gcc/msp430/4.6.3/../../../../msp430/bin/ld: region `rom' overflowed by 88 bytes
gateway.co: In function `process_thread_init_mesh':
gateway.c:(.text.process_thread_init_mesh+0x10): undefined reference to `mesh_close'
gateway.c:(.text.process_thread_init_mesh+0x26): undefined reference to `mesh_open'
gateway.co: In function `recv':
gateway.c:(.text.recv+0x48): undefined reference to `mesh_send'
gateway.co: In function `enable_handler':
gateway.c:(.text.enable_handler+0x80): undefined reference to `mesh_send'
collect2: ld returned 1 exit status
../../Makefile.include:254: recipe for target 'gateway.sky' failed
Process returned error code 2
make: *** [gateway.sky] Error 1
rm obj_sky/contiki-sky-main.o gateway.co
Makefile
all: gateway mote
ifndef TARGET
TARGET=sky
endif
CONTIKI=../..
WITH_UIP6=1
UIP_CONF_IPV6=1
WITH_COAP = 0
APPS += rest-http
include $(CONTIKI)/Makefile.include
Lines to compile for REST
WITH_UIP6=1
UIP_CONF_IPV6=1
WITH_COAP = 0
APPS += rest-http
gateway.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "contiki.h"
#include "contiki-net.h"
#include "rest.h"
#include "net/rime.h"
#include "net/rime/mesh.h"
#if defined (PLATFORM_HAS_LIGHT)
#include "dev/light-sensor.h"
#endif
#if defined (PLATFORM_HAS_BATT)
#include "dev/battery-sensor.h"
#endif
#if defined (PLATFORM_HAS_SHT11)
#include "dev/sht11-sensor.h"
#endif
#if defined (PLATFORM_HAS_LEDS)
#include "dev/leds.h"
#endif
#define DEBUG 1
#if DEBUG
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__)
#define PRINT6ADDR(addr) PRINTF(" %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x ", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15])
#define PRINTLLADDR(lladdr) PRINTF(" %02x:%02x:%02x:%02x:%02x:%02x ",(lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3],(lladdr)->addr[4], (lladdr)->addr[5])
#else
#define PRINTF(...)
#define PRINT6ADDR(addr)
#define PRINTLLADDR(addr)
#endif
#define MESSAGE "Hello"
/*---------------------------------------------------------------------------*/
/*---------------------------------RIME--------------------------------------*/
/*---------------------------------------------------------------------------*/
static struct mesh_conn mesh;
PROCESS(init_mesh, "RIME Mesh");
/*---------------------------------------------------------------------------*/
static void
sent(struct mesh_conn *c)
{
printf("packet sent\n");
}
static void
timedout(struct mesh_conn *c)
{
printf("packet timedout\n");
}
static void
recv(struct mesh_conn *c, const rimeaddr_t *from, uint8_t hops)
{
printf("Data received from %d.%d: %.*s (%d)\n",
from->u8[0], from->u8[1],
packetbuf_datalen(), (char *)packetbuf_dataptr(), packetbuf_datalen());
packetbuf_copyfrom(MESSAGE, strlen(MESSAGE));
mesh_send(&mesh, from);
}
static void
send(int to, char * msg)
{
printf("Sending data to %d", to);
rimeaddr_t addr;
packetbuf_copyfrom(msg, strlen(msg));
addr.u8[0] = to;
addr.u8[1] = 0;
mesh_send(&mesh, &addr);
}
const static struct mesh_callbacks callbacks = {recv, sent, timedout};
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(init_mesh, ev, data)
{
PROCESS_EXITHANDLER(mesh_close(&mesh);)
PROCESS_BEGIN();
mesh_open(&mesh, 132, &callbacks);
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
/*----------------------------------REST-------------------------------------*/
/*---------------------------------------------------------------------------*/
RESOURCE(enable, METHOD_GET, "enable");
void
enable_handler(REQUEST* request, RESPONSE* response)
{
int moteId = 0;
char moteIdstr[12];
sprintf(moteIdstr, "%d", moteId);
char command[20];
char responseText[255];
if (rest_get_query_variable(request, "moteId", moteIdstr, 10)) {
PRINTF("moteId %s\n", moteIdstr);
send(moteId, command);
sprintf(responseText,"Command execute for mote %s!\n", moteIdstr);
} else {
sprintf(responseText,"Mote not available!\n");
}
rest_set_header_content_type(response, TEXT_PLAIN);
rest_set_response_payload(response, (uint8_t*)responseText, strlen(responseText));
}
PROCESS(gateway_rest, "Gateway Rest");
PROCESS_THREAD(gateway_rest, ev, data)
{
PROCESS_BEGIN();
#ifdef WITH_COAP
PRINTF("COAP Server\n");
#else
PRINTF("HTTP Server\n");
#endif
rest_init();
rest_activate_resource(&resource_enable);
//rest_activate_resource(&resource_disable);
PROCESS_END();
}
/*---------------*/
AUTOSTART_PROCESSES(&init_mesh, &gateway_rest);
Info
I am using Sky motes to compile the code in Cooja.

Cannot wrap cgo flags with macros

I made a Go program to simulate key presses. To do that I had to use cgo and different snippet of C code depending on the OS the Go code was being compiled.
The code that I wrote looks like this:
package keyboard
/*
#include <stdint.h>
#ifdef __WIN32
#cgo CFLAGS:-nostdlib
#include <Windows.h>
void SetKey(uint16_t key, uint8_t value) {
INPUT ip;
ip.type = INPUT_KEYBOARD;
ip.ki.wScan = 0;
ip.ki.time = 0;
ip.ki.dwExtraInfo = 0;
ip.ki.wVk = key;
if (value) {
ip.ki.dwFlags = 0;
} else {
ip.ki.dwFlags = KEYEVENTF_KEYUP;
}
SendInput(1, &ip, sizeof(INPUT));
}
#endif
#ifdef __linux__
#cgo LDFLAGS: -lX11 -lXtst
#include <stdlib.h>
#include <stdio.h> //TODO: REMOVE
#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <X11/extensions/XTest.h>
void SetKey(uint16_t key, uint8_t value) {
Display *display;
display = XOpenDisplay(NULL);
if(display == NULL) {
exit(EXIT_FAILURE);
}
XTestFakeKeyEvent(display,XKeysymToKeycode(display,key), value, 0);
XCloseDisplay(display);
}
#endif
*/
import "C"
func SetKey(keyId uint16, value bool) {
C.SetKey(C.uint16_t(keyId),boolToByte(value));
}
func boolToByte(value bool) C.uint8_t {
if(value) {
return 1
} else {
return 0
}
}
The code compiles fine on Ubuntu, but on Windows 10 I get the following error
C:/TDM-GCC-64/bin/../lib/gcc/x86_64-w64-mingw32/5.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: cannot find -lX11
C:/TDM-GCC-64/bin/../lib/gcc/x86_64-w64-mingw32/5.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: cannot find -lXtst
even if the line #cgo LDFLAGS: -lX11 -lXtst is wrapped around #ifdef __linux__ and #endif.
Where does the problem lie on?
Does the GCC compiler define the __linux__ macro?
Is the keyword #cgo not supposed to be used like that?
The #cgo directives are used by the go tools, not the C pre-processor.
In the cgo documentation, there are examples of using build constraints to conditionally set the flag values. What you want is
#cgo windows CFLAGS:-nostdlib
#cgo linux LDFLAGS: -lX11 -lXtst

Getting the saved instruction pointer address from a signal handler

My question is somewhat different from others that have asked about fault addresses. I'm trying to implement a horrible hack to determine, from a signal handler, whether the signal interrupted a syscall or ordinary user code by inspecting the code at the saved instruction pointer and comparing it against the possible syscall entry instructions for the host architecture it's running on. This is part of implementing correct POSIX thread cancellation that does not suffer from the race condition and resource leak described in my old question:
How are POSIX cancellation points supposed to behave?
If this approach is unreliable or otherwise wrong, I'd also like to hear reasons.
/* sigsegv.c */
/**
* This source file is used to print out a stack-trace when your program
* segfaults. It is relatively reliable and spot-on accurate.
*
* This code is in the public domain. Use it as you see fit, some credit
* would be appreciated, but is not a prerequisite for usage. Feedback
* on it's use would encourage further development and maintenance.
*
* Due to a bug in gcc-4.x.x you currently have to compile as C++ if you want
* demangling to work.
*
* Please note that it's been ported into my ULS library, thus the check for
* HAS_ULSLIB and the use of the sigsegv_outp macro based on that define.
*
* Author: Jaco Kroon <jaco#kroon.co.za>
*
* Copyright (C) 2005 - 2010 Jaco Kroon
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
/* Bug in gcc prevents from using CPP_DEMANGLE in pure "C" */
#if !defined(__cplusplus) && !defined(NO_CPP_DEMANGLE)
#define NO_CPP_DEMANGLE
#endif
#include <memory.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <ucontext.h>
#include <dlfcn.h>
#ifndef NO_CPP_DEMANGLE
#include <cxxabi.h>
#ifdef __cplusplus
using __cxxabiv1::__cxa_demangle;
#endif
#endif
#ifdef HAS_ULSLIB
#include "uls/logger.h"
#define sigsegv_outp(x) sigsegv_outp(,gx)
#else
#define sigsegv_outp(x, ...) fprintf(stderr, x "\n", ##__VA_ARGS__)
#endif
#if defined(REG_RIP)
# define SIGSEGV_STACK_IA64
# define REGFORMAT "%016lx"
#elif defined(REG_EIP)
# define SIGSEGV_STACK_X86
# define REGFORMAT "%08x"
#else
# define SIGSEGV_STACK_GENERIC
# define REGFORMAT "%x"
#endif
static void signal_segv(int signum, siginfo_t* info, void*ptr) {
static const char *si_codes[3] = {"", "SEGV_MAPERR", "SEGV_ACCERR"};
int i, f = 0;
ucontext_t *ucontext = (ucontext_t*)ptr;
Dl_info dlinfo;
void **bp = 0;
void *ip = 0;
sigsegv_outp("Segmentation Fault!");
sigsegv_outp("info.si_signo = %d", signum);
sigsegv_outp("info.si_errno = %d", info->si_errno);
sigsegv_outp("info.si_code = %d (%s)", info->si_code, si_codes[info->si_code]);
sigsegv_outp("info.si_addr = %p", info->si_addr);
for(i = 0; i < NGREG; i++)
sigsegv_outp("reg[%02d] = 0x" REGFORMAT, i, ucontext->uc_mcontext.gregs[i]);
#ifndef SIGSEGV_NOSTACK
#if defined(SIGSEGV_STACK_IA64) || defined(SIGSEGV_STACK_X86)
#if defined(SIGSEGV_STACK_IA64)
ip = (void*)ucontext->uc_mcontext.gregs[REG_RIP];
bp = (void**)ucontext->uc_mcontext.gregs[REG_RBP];
#elif defined(SIGSEGV_STACK_X86)
ip = (void*)ucontext->uc_mcontext.gregs[REG_EIP];
bp = (void**)ucontext->uc_mcontext.gregs[REG_EBP];
#endif
sigsegv_outp("Stack trace:");
while(bp && ip) {
if(!dladdr(ip, &dlinfo))
break;
const char *symname = dlinfo.dli_sname;
#ifndef NO_CPP_DEMANGLE
int status;
char * tmp = __cxa_demangle(symname, NULL, 0, &status);
if (status == 0 && tmp)
symname = tmp;
#endif
sigsegv_outp("% 2d: %p <%s+%lu> (%s)",
++f,
ip,
symname,
(unsigned long)ip - (unsigned long)dlinfo.dli_saddr,
dlinfo.dli_fname);
#ifndef NO_CPP_DEMANGLE
if (tmp)
free(tmp);
#endif
if(dlinfo.dli_sname && !strcmp(dlinfo.dli_sname, "main"))
break;
ip = bp[1];
bp = (void**)bp[0];
}
#else
sigsegv_outp("Stack trace (non-dedicated):");
sz = backtrace(bt, 20);
strings = backtrace_symbols(bt, sz);
for(i = 0; i < sz; ++i)
sigsegv_outp("%s", strings[i]);
#endif
sigsegv_outp("End of stack trace.");
#else
sigsegv_outp("Not printing stack strace.");
#endif
_exit (-1);
}
static void __attribute__((constructor)) setup_sigsegv() {
struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_sigaction = signal_segv;
action.sa_flags = SA_SIGINFO;
if(sigaction(SIGSEGV, &action, NULL) < 0)
perror("sigaction");
}
$ g++ -fPIC -shared -o libsigsegv.so -ldl sigsegv
$ export LD_PRELOAD=/path/to/libsigsegv.so
I found this code on a LUG. Couldn't get to the page to point the URL here, so pasted the whole code. This code prints a small stack trace when SIGSEGV occurs. Not sure if there is some other way that does not use ucontext_t.

Resources