With the header file (UDPRBPlib.h) and the implementation file (UDPRBPlib.c) I keep getting errors of multiple definitions for global variables and all of my functions shown below:
/usr/bin/ld: /tmp/ccTq4sS2.o:/home/UDPRBPlib.h:14: multiple definition of `set'; /tmp/ccuctEs0.o:/home/UDPRBPlib.h:14: first defined here
/usr/bin/ld: /tmp/ccTq4sS2.o:/home/UDPRBPlib.h:15: multiple definition of `get'; /tmp/ccuctEs0.o:/home/UDPRBPlib.h:15: first defined here
/usr/bin/ld: /tmp/ccTq4sS2.o:/home/UDPRBPlib.h:16: multiple definition of `run'; /tmp/ccuctEs0.o:/home/UDPRBPlib.h:16: first defined here
/usr/bin/ld: /tmp/ccTq4sS2.o:/home/UDPRBPlib.h:17: multiple definition of `stop'; /tmp/ccuctEs0.o:/home/UDPRBPlib.h:17: first defined here
/usr/bin/ld: /tmp/ccTq4sS2.o:/home/UDPRBPlib.h:26: multiple definition of `server_struct_length'; /tmp/ccuctEs0.o:/home/UDPRBPlib.h:26: first defined here
/usr/bin/ld: /tmp/ccTq4sS2.o: in function `RBPCurrentConvert':
/home/UDPRBPlib.c:4: multiple definition of `RBPCurrentConvert'; /tmp/ccuctEs0.o:/home/UDPRBPlib.c:4: first defined here
/usr/bin/ld: /tmp/ccTq4sS2.o: in function `sendUDPMsg':
/home/UDPRBPlib.c:12: multiple definition of `sendUDPMsg'; /tmp/ccuctEs0.o:/home/UDPRBPlib.c:12: first defined here
/usr/bin/ld: /tmp/ccTq4sS2.o: in function `UDPinit':
/home/UDPRBPlib.c:54: multiple definition of `UDPinit'; /tmp/ccuctEs0.o:/home/UDPRBPlib.c:54: first defined here
/usr/bin/ld: /tmp/ccTq4sS2.o: in function `RBPSendSetpt':
/home/UDPRBPlib.c:76: multiple definition of `RBPSendSetpt'; /tmp/ccuctEs0.o:/home/UDPRBPlib.c:76: first defined here
/usr/bin/ld: /tmp/ccTq4sS2.o: in function `FTFToggle':
/home/UDPRBPlib.c:106: multiple definition of `FTFToggle'; /tmp/ccuctEs0.o:/home/UDPRBPlib.c:106: first defined here
/usr/bin/ld: /tmp/ccTq4sS2.o: in function `RBPSetRemote':
/home/UDPRBPlib.c:122: multiple definition of `RBPSetRemote'; /tmp/ccuctEs0.o:/home/UDPRBPlib.c:122: first defined here
collect2: error: ld returned 1 exit status
Header file (UDPRBPlib.h):
#ifndef UDPRBPLIB_H
#define UDPRBPLIB_H
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdint.h>
#include <unistd.h>
uint8_t client_message[1];
uint8_t set = 0x73;
uint8_t get = 0x67;
uint8_t run = 0x18;
uint8_t stop = 0x02;
// INIT
//#define DEBUGMODE 1
int socket_desc;
struct sockaddr_in server_addr;
char server_message[60];
// SEND MSG
int server_struct_length = sizeof(server_addr);
struct setpt{
uint16_t setptValue; // thing we're sending // [9] and [10] in RBPSendSetpt function
uint8_t signflag; // RBP only takes positive numbers, the sign is to be communication in terms of charge and discharge signified by this flag
uint8_t cktNum;
int mode; // 1 for cc and 0 for cv
int runOrStop; // 1 for run; 0 for stop
int setOrGet; // 1 for set; 0 for get
};
uint16_t RBPCurrentConvert(float x);
int sendUDPMsg();
int UDPinit();
void RBPSendSetpt(const struct setpt tmp);
void FTFToggle(const struct setpt tmp);
void RBPSetRemote(const struct setpt tmp);
#endif
Implementation file (UDPRBPlib.c):
#include "UDPRBPlib.h"
// will convert x to the proper format
uint16_t RBPCurrentConvert(float x){
x = fabs(x);
x *= 100;
x = roundf(x);
uint16_t y = x;
return y;
}
int sendUDPMsg(){
int length = sizeof(client_message)/sizeof(client_message[0]);
#ifdef DEBUGMODE
printf("Sending message:");
printf("\n");
#endif
for(uint16_t i=0; i<sizeof(client_message); i++){
printf("0x%X\t", client_message[i]);
if ((i + 1) % 15 == 0) printf("\n");
}
// Send the message to server:
if(sendto(socket_desc, client_message, sizeof(client_message), 0, (struct sockaddr*)&server_addr, server_struct_length) < 0){
printf("Unable to send message\n");
return -1;
}
// Receive the server's response:
if(recvfrom(socket_desc, server_message, sizeof(server_message), 0, (struct sockaddr*)&server_addr, &server_struct_length) < 0){
printf("Error while receiving server's msg\n");
return -1;
}
printf("\nReceived message:");
for(uint16_t i=0; i<sizeof(server_message); i++){
if(i%15 == 0)
printf("\n");
printf("0x%X\t", server_message[i]);
}
printf("\n");
// error check: see if what was returned was the same as what was sent
for(int i = 0; i < length; i++){
if(server_message[i] != client_message[i])
printf("Error in server message at index %d\n", i);
}
// Close the socket:
close(socket_desc);
return 0;
}
int UDPinit(){
// Clean buffers:
memset(server_message, '\0', sizeof(server_message)); //init
//memset(client_message, '\0', sizeof(client_message));
// Create socket: in init
socket_desc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(socket_desc < 0){
printf("Error while creating socket\n");
return -1;
}
printf("Socket created successfully\n");
// Set port and IP: init
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(36112);
server_addr.sin_addr.s_addr = inet_addr("169.254.0.1");
return 0;
}
// assembles the message and returns a pointer to the message
void RBPSendSetpt(const struct setpt tmp){
client_message[19];
client_message[0] = 0x01; // Rack Control Address
client_message[1] = tmp.cktNum;
client_message[2] = 0x43; // mandatory
client_message[3] = 0x53; // mandatory
if(tmp.setOrGet == 1)
client_message[4] = set;
else if(tmp.setOrGet == 0)
client_message[4] = get;
client_message[7] = 0x00; // current
client_message[8] = 0x00;
sendUDPMsg();
return;
}
// assemles the message in run OR stop state
void FTFToggle(const struct setpt tmp){
client_message[5];
client_message[0] = 0x01;
client_message[1] = tmp.cktNum;
client_message[2] = 0x4C;
client_message[3] = 0x52;
if(tmp.runOrStop == 1)
client_message[4] = run;
else if(tmp.runOrStop == 0)
client_message[4] = stop;
sendUDPMsg();
return;
}
// assemles the message
void RBPSetRemote(const struct setpt tmp){
client_message[6];
client_message[0] = 0x01;
client_message[1] = tmp.cktNum;
client_message[2] = 0x4C;
client_message[3] = 0x30;
if(tmp.setOrGet == 1)
client_message[4] = set;
else if(tmp.setOrGet == 0)
client_message[4] = get;
client_message[5] = 0x01;
sendUDPMsg();
return;
}
If I put all the code in one file, it seems to run correctly, but when the code is in two different files, I get the above errors. I suspect there is something wrong with my headers in the respective files, but nothing I've tried has worked.
The problem is that you're defining variables (e.g. uint8_t get = 0x67;) in your .h file, which means that you're defining those variables in every .c file that #include's that .h file; hence the "multiple definition" errors.
To avoid that, you'll either need to change those definitions to declarations (e.g. extern uint8_t get;) in your .h file, and then a separate uint8_t get = 0x67; in exactly one .c file), or if they are intended to be constants, you could replace them with macros (e.g. #define get 0x67, although I'd strongly recommend a less generic name in that case, e.g. #define MY_PROGRAM_CONSTANT_GET 0x67, to avoid accidentally treading on other code's use of the same string.
You have these lines in the header:
int socket_desc;
struct sockaddr_in server_addr;
char server_message[60];
Those are variable definitions. Every file that includes the header defines those variables. When you link two such files, the symbols are multiply defined.
Declare variables in headers — with extern:
extern int socket_desc;
extern struct sockaddr_in server_addr;
extern char server_message[60];
Note you can't use an initializer.
Once upon a while ago, in versions of GCC before GCC 10, the default behaviour was to make such definitions into 'common' variables, and those could be 'multiply defined'. The 'common' is named after Fortran COMMON blocks. With GCC 10 and later, the default behaviour is to make those non-common definitions. If you're really stuck with ancient code that you can't modify, you may have to override the modern default option -fno-common with an explicit -fcommon in the build process. It isn't recommended. The standard always said that this was incorrect, but recognized it as a common extension, with the double entendre fully intended.
See also How do I use extern to share variables between source files?
Incidentally, note that unless you're using C23 (or later), the lines:
int sendUDPMsg();
int UDPinit();
declare the functions sendUDPMsg() and UPDinit(), but they do do not provide prototypes for the functions — so they can be called with any sequence of arguments. If your functions take no arguments, say so explicitly:
int sendUDPMsg(void);
int UDPinit(void);
Related
Is it possible to send double values using the TCP/IP client block in the Simulink Support Package for Raspberry Pi?
I have been stuck for a while trying to get this to work:
but using printf("%f %f %f", *((double *)tcp_buffer)), *((double *)tcp_buffer + 1)), *((double *)tcp_buffer + 2))) only prints zeros.
This, however, works ok (printing an int):
After trying to get this working for quite a while, I am under the impression that it will not work (or there is a rather obscured way of doing it). I wound up implementing my own TCP/IP client device driver (i.e. a Simulink block similar to the ones provided by the package) to do the trick and thought I'd leave my implementation here for anyone that's looking. (I think it's better that way anyway as you can really define how you want your client to work.)
To create the device driver, one would need to follow the instructions found on the MATHWORKS site here.
My C implementation for the client is as follows:
/* File: client.h */
#ifndef _CLIENT_H_
#define _CLIENT_H_
#include "rtwtypes.h"
extern int socket_desc;
void init_socket_comm(void);
void send_socket_data(void);
void close_socket(void);
#endif /* _CLIENT_H */
and
/* File: client.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include "client.h"
int socket_desc;
int_T init_socket_comm(void)
{
struct sockaddr_in server; /* Server socket parameters */
/* Create socket and get socket descriptor */
socket_desc = socket(AF_INET, SOCK_STREAM, 0);
if (socket_desc < 0)
{
fprintf(stderr, "Could not create socket\n");
exit(EXIT_FAILURE);
}
/* Specify parameters for server socket */
server.sin_addr.s_addr = inet_addr("127.0.0.1"); /* Server TCP IP;
server.sin_family = AF_INET;
server.sin_port = htons(25000); /* TCP port */;
/* Connect socket to server */
if (connect(socket_desc, (struct sockaddr *)&server, sizeof(server)) < 0)
{
fprintf(stderr, "Could not connect to server\n");
/* Close socket */
close(socket_desc);
printf("Socket closed successfully.\n");
exit(EXIT_FAILURE);
}
return socket_desc;
}
/* Sends an array of doubles. */
void send_socket_data(void)
{
int buffer_size = 56;
real_T buffer[7] = {3.21232, 5.31453, 10.34108, 7.34652, 2.34524, 4.44432, 3.45642};
unsigned char *buffer_ptr = (unsigned char *)buffer;
int sent_size;
/* Send data to server */
while (buffer_size > 0)
{
if ((sent_size = send(socket_desc, buffer, buffer_size, 0)) < 0)
{
fprintf(stderr, "Send failed.\n");
/* Close socket */
close(socket_desc);
printf("Socket closed successfully.\n");
exit(EXIT_FAILURE);
}
buffer_ptr += sent_size;
buffer_size -= sent_size;
}
}
void close_socket(void)
{
/* Close socket */
close(socket_desc);
}
Next, you'd need you System Object (I named mine TcpClient):
% File: TcpClient.m
classdef TcpClient < matlab.System & coder.ExternalDependency
%
% System object TcpClient block.
properties
% Public, tunable properties.
end
properties (Nontunable)
% Public, non-tunable properties.
end
properties (Access = private)
% Pre-computed constants.
end
methods
% Constructor
function obj = TcpClient(varargin)
% Support name-value pair arguments when constructing the object.
setProperties(obj,nargin,varargin{:});
end
end
methods (Access=protected)
function setupImpl(obj) %#ok<MANU>
if isempty(coder.target)
% Place simulation setup code here
else
% Call C-function implementing device initialization
coder.cinclude('client.h');
coder.ceval('init_socket_comm');
end
end
function stepImpl(obj,u) %#ok<INUSD>
if isempty(coder.target)
% Place simulation output code here
else
% Call C-function implementing device output
coder.ceval('send_socket_data');
end
end
function releaseImpl(obj) %#ok<MANU>
if isempty(coder.target)
% Place simulation termination code here
else
% Call C-function implementing device termination
coder.ceval('close_socket');
end
end
end
methods (Access=protected)
%% Define input properties
function num = getNumInputsImpl(~)
num = 1;
end
function num = getNumOutputsImpl(~)
num = 0;
end
function flag = isInputSizeMutableImpl(~,~)
flag = false;
end
function flag = isInputComplexityMutableImpl(~,~)
flag = false;
end
function validateInputsImpl(~, u)
if isempty(coder.target)
% Run input validation only in Simulation
validateattributes(u,{'double'},{'scalar'},'','u');
end
end
function icon = getIconImpl(~)
% Define a string as the icon for the System block in Simulink.
icon = 'Sink';
end
end
methods (Static, Access=protected)
function simMode = getSimulateUsingImpl(~)
simMode = 'Interpreted execution';
end
function isVisible = showSimulateUsingImpl
isVisible = false;
end
end
methods (Static)
function name = getDescriptiveName()
name = 'Sink';
end
function b = isSupportedContext(context)
b = context.isCodeGenTarget('rtw');
end
function updateBuildInfo(buildInfo, context)
if context.isCodeGenTarget('rtw')
% Update buildInfo
srcDir = fullfile(fileparts(mfilename('fullpath')),'src'); %#ok<NASGU>
includeDir = fullfile(fileparts(mfilename('fullpath')),'include');
addIncludePaths(buildInfo,includeDir);
% Use the following API's to add include files, sources and
addSourceFiles(buildInfo,'client.c', srcDir);
end
end
end
end
Now you can send doubles and if you create your server correctly using the code from here which I adapted to create a function that reads the TCP buffer:
/* File: server.c */
int read_socket_data(int new_socket, void *buffer, int buffer_size)
{
int read_size;
int read_attempts;
/* Continously read TCP buffer */
while ((read_size = recv(new_socket, buffer, buffer_size, 0)) >= 0)
{
if (read_size > 0)
{
/* Print read buffer */
for (int offset = 0; offset < 7; offset++)
{
printf("%lf\n", *((double *)buffer + offset));
}
}
}
return read_size;
}
you can read and print the doubles correctly.
I have this function which is depreciated. First how one can find the new alternative to functions that are depreciated. the function exist in libbpf library and perf_buffer__new is the exact name. so basically as the name suggest its used to create perf buffer to share info between userspace and kernel. First I like to know is perf buffers are only specific to ebpf filters or not. not means I can use perf buffers in anything. for example if I have some driver code so I just add perf buffer to have info shared between some userspace app and the driver. so some searching on the web I found it specifically link to ebpf, is this true?
So this is my code that uses call to perf_buffer__new but that function is depreciated, this function in libbpf's libbpf.h header file declarations is commented out
So I like to new what is the new alternative that I can use in my code, if there is a change in api then i like to let u know that I am trying share buffer parameter in SEC("kprobe/__x64_sys_recvfrom") to userspace for that I have used PT_REGS_PARM2 and bpf_probe_read_kernel to and included the parameter in map data. So if api is changed then how to accomplish this this is my userspace and ebpf program
Userspace.c
// SPDX-License-Identifier: GPL-2.0-only
#include <stdio.h>
#include <fcntl.h>
#include <poll.h>
#include <time.h>
#include <signal.h>
#include <bpf/libbpf.h>
//create .o file root#this:/home/ubuntu/Desktop/ebpf/kern# clang -I /lib/modules/5.14.1/build -I /usr/include/bpf/ -O2 -Wall -c trace_output_user.c
static __u64 time_get_ns(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec * 1000000000ull + ts.tv_nsec;
}
static __u64 start_time;
static __u64 cnt;
#define MAX_CNT 100000ll
static void print_bpf_output(void *ctx, int cpu, void *data, __u32 size)
{
struct {
int pid;
char cookie[90];
char *buf;
} *e = data;
int i=0;
printf("hello\n");
printf(" _____________________________________________________%d \n________%s\n",e->pid,e->buf);
i++;
//printf("received map value = %s\n",e->cookie);
/*if (e->cookie != 0x12345678) {
printf("BUG pid %llx cookie %d sized %d\n",
e->pid, e->cookie, size);
return;
}
cnt++;
if (cnt == MAX_CNT) {
printf("recv %lld events per sec\n",
MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
return;
}*/
}
int main(int argc, char **argv)
{
struct perf_buffer_opts pb_opts = {};
struct bpf_link *link = NULL;
struct bpf_program *prog;
struct perf_buffer *pb;
struct bpf_object *obj;
int map_fd, ret = 0;
char filename[256];
FILE *f;
//snprintf(filename, sizeof(filename), "..o", argv[0]);
obj = bpf_object__open_file("./kprobe_send.o", NULL);
if (libbpf_get_error(obj)) {
fprintf(stderr, "ERROR: opening BPF object file failed\n");
return 0;
}
/* load BPF program */
if (bpf_object__load(obj)) {
fprintf(stderr, "ERROR: loading BPF object file failed\n");
goto cleanup;
}
map_fd = bpf_object__find_map_fd_by_name(obj, "my_map");
if (map_fd < 0) {
fprintf(stderr, "ERROR: finding a map in obj file failed\n");
goto cleanup;
}
printf("before\n");
prog = bpf_object__find_program_by_name(obj, "bpf_prog1");
if (libbpf_get_error(prog)) {
fprintf(stderr, "ERROR: finding a prog in obj file failed\n");
goto cleanup;
}
printf("after\n");
link = bpf_program__attach(prog);
printf("after\n");
if (libbpf_get_error(link)) {
fprintf(stderr, "ERROR: bpf_program__attach failed\n");
link = NULL;
goto cleanup;
}
printf("after\n");
pb_opts.sample_cb = print_bpf_output;
pb = perf_buffer__new_deprecated(map_fd, 8, &pb_opts);//error
printf("after\n");
ret = libbpf_get_error(pb);
if (ret) {
printf("failed to setup perf_buffer: %d\n", ret);
return 1;
}
f = popen("taskset 1 dd if=/dev/zero of=/dev/null", "r");
(void) f;
start_time = time_get_ns();
while ((ret = perf_buffer__poll(pb, 1000)) >= 0 && cnt < MAX_CNT) {
}
kill(0, SIGINT);
cleanup:
bpf_link__destroy(link);
bpf_object__close(obj);
return ret;
}
Kernel.c
#include <linux/ptrace.h>
#include <linux/version.h>
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <string.h>
#include <sys/sendfile.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include </usr/include/bpf/bpf_tracing.h>
#include <linux/seccomp.h>
#define RAND_MAX 0x7fff
#define PERF_SAMPLE_RAW 1U << 0
#define randrange(N) rand() / (RAND_MAX/(N) + 1)
#define MAX 100000000 /* Values will be in the range (1 .. MAX) */
struct {
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
__uint(key_size, sizeof(int));
__uint(value_size, sizeof(int));
__uint(max_entries, 100);
} my_map SEC(".maps");
SEC("kprobe/__x64_sys_recvfrom")
int bpf_prog1(struct pt_regs *ctx)
{
static int vektor[100000000];
int candidates[MAX];
int i;
long key;
//srand(time(NULL)); /* Seed the random number generator. */
/*for (i=0; i<MAX; i++)
candidates[i] = i;
for (i = 0; i < MAX-1; i++) {
int c = randrange(MAX-i);
int t = candidates[i];
candidates[i] = candidates[i+c];
candidates[i+c] = t;
}
for (i=0; i<10; i++)
vektor[i] = candidates[i] + 1;*/
struct S {
int pid;
char cookie[90];
char *ptr;
} data={1,""};
//char *ptr = PT_REGS_PARM2(ctx);
struct seccomp_data sd;
bpf_probe_read_kernel(&sd, sizeof(sd), (void *)PT_REGS_PARM2(ctx));
if (sd.args[2] > 128 && sd.args[2] <= 1024) {
char fmt[] = "read(fd=%d, buf=%p, size=%d)\n";
bpf_trace_printk(fmt, sizeof(fmt),
sd.args[0], sd.args[1], sd.args[2]);
data.ptr=(char *)sd.args[1];
// memcpy(data.ptr,sd.args[1],sizeof(char)*220);
}
//data.pid =count;// bpf_get_current_pid_tgid();
//if(buf==NULL)
//memcpy(data.cookie,buf,20);
//data.ptr=ptr;
// data.cookie[0]=buf[0];
//bpf_get_current_comm(&data.cookie, sizeof(data.cookie));
//key=vektor[i];
//bpf_map_update_elem(fd,&key,&data,BPF_ANY);
//bpf_perf_event_output(ctx, &my_map, 1, &data, sizeof(data));
return 0;
}
char _license[] SEC("license") = "GPL";
int _version SEC("version") = 99;
when I compile and link the program userspace with root#this:/home/ubuntu/Desktop/ebpf/Linux-exFilter-main/pkg/probe/bpf# clang -v trace_output_user.c -o trace -lbpf
I get error that and warning
trace_output_user.c:101:7: warning: 'perf_buffer__new_deprecated' is deprecated: libbpf v0.7+: use new variant of perf_buffer__new() instead [-Wdeprecated-declarations]
pb = perf_buffer__new_deprecated(map_fd, 8, &pb_opts);
^
/usr/include/bpf/libbpf.h:949:12: note: 'perf_buffer__new_deprecated' has been explicitly marked deprecated here
LIBBPF_API LIBBPF_DEPRECATED_SINCE(0, 7, "use new variant of perf_buffer__new() instead")
^
/usr/include/bpf/libbpf_common.h:24:4: note: expanded from macro 'LIBBPF_DEPRECATED_SINCE'
(LIBBPF_DEPRECATED("libbpf v" # major "." # minor "+: " msg))
^
/usr/include/bpf/libbpf_common.h:19:47: note: expanded from macro 'LIBBPF_DEPRECATED'
#define LIBBPF_DEPRECATED(msg) __attribute__((deprecated(msg)))
^
1 warning generated.
"/usr/bin/ld" -z relro --hash-style=gnu --build-id --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o trace /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../x86_64-linux-gnu/crt1.o /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../x86_64-linux-gnu/crti.o /usr/bin/../lib/gcc/x86_64-linux-gnu/10/crtbegin.o -L/usr/bin/../lib/gcc/x86_64-linux-gnu/10 -L/usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../x86_64-linux-gnu -L/usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../lib64 -L/lib/x86_64-linux-gnu -L/lib/../lib64 -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib64 -L/usr/lib/x86_64-linux-gnu/../../lib64 -L/usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../.. -L/usr/lib/llvm-12/bin/../lib -L/lib -L/usr/lib /tmp/trace_output_user-ec780e.o -lbpf -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/bin/../lib/gcc/x86_64-linux-gnu/10/crtend.o /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../x86_64-linux-gnu/crtn.o
/usr/bin/ld: /tmp/trace_output_user-ec780e.o: in function `main':
trace_output_user.c:(.text+0x1e2): undefined reference to `perf_buffer__new_deprecated'
some details
perf_buffer__new_deprecated
and
perf_buffer__new are depreciated in latest version of libbpf
My kernel version is 5.14.1
1. you are explicitly using perf_buffer__new_deprecated in your code - don't do this: Use perf_buffer_new instead. You should never call a function that already has 'deprecated' in it's name.
2. Take a look in the header:
libbpf/libbpf.h
perf_buffer_new is defined like this:
#define perf_buffer__new(...) ___libbpf_overload(___perf_buffer_new, __VA_ARGS__)
#define ___perf_buffer_new6(map_fd, page_cnt, sample_cb, lost_cb, ctx, opts) \
perf_buffer__new(map_fd, page_cnt, sample_cb, lost_cb, ctx, opts)
#define ___perf_buffer_new3(map_fd, page_cnt, opts) \
perf_buffer__new_deprecated(map_fd, page_cnt, opts)
So there are 2 functions:
Old: pef_buffer_new with 3 arguments
New: perf_buffer_new with 6 arguments.
With the macros, libbpf makes old code compile, too, while telling you to change your function call.
You are using the old version right now (with 3 arguments). Switch to the new version with 6 arguments, as the 3-arguments-variant will be removed.
The new function (see libbpf/libbpf.h):
/**
* #brief **perf_buffer__new()** creates BPF perfbuf manager for a specified
* BPF_PERF_EVENT_ARRAY map
* #param map_fd FD of BPF_PERF_EVENT_ARRAY BPF map that will be used by BPF
* code to send data over to user-space
* #param page_cnt number of memory pages allocated for each per-CPU buffer
* #param sample_cb function called on each received data record
* #param lost_cb function called when record loss has occurred
* #param ctx user-provided extra context passed into *sample_cb* and *lost_cb*
* #return a new instance of struct perf_buffer on success, NULL on error with
* *errno* containing an error code
*/
LIBBPF_API struct perf_buffer *
perf_buffer__new(int map_fd, size_t page_cnt,
perf_buffer_sample_fn sample_cb, perf_buffer_lost_fn lost_cb, void *ctx,
const struct perf_buffer_opts *opts);
You can find the definitions for sample_cb and lost_cb in the header as well:
From above, we know sample_cb has the type perf_buffer_sample_fn. For the other callback, it is similar.
Both are defined in libbpf.h:
typedef void (*perf_buffer_sample_fn)(void *ctx, int cpu,
void *data, __u32 size);
typedef void (*perf_buffer_lost_fn)(void *ctx, int cpu, __u64 cnt);
See libbpf/libbpf.h
So a valid callback function could be
void myCallbackForNewData(void* ctx, int cpu, void*data, __u32 size) {}
Be aware that ctx* has nothing to do with BPF - it is something you can freely define in perf_buffer__new. This is useful if you use the same handler for multiple perf_buffers. Otherwise, you can just enter NULL.
I am trying to write a C program using the I/O call system in Ubuntu.
I found this documentation, CDROM API from Linux-sxs.org, but I don't understand where to find those arguments.
Can you please give me an example about how to use the ioctl() function?
struct cdrom_read_audio ra
{
union cdrom_addr addr; /* REQUIRED frame address */
u_char addr_format; /* REQUIRED .....CDROM_LBA or CDROM_MSF */
int nframes; /* REQUIRED number of 2352-byte-frames to read*/
u_char *buf; /* REQUIRED frame buffer (size: nframes*2352 bytes) */
};
if (ioctl(cdrom, CDROMREADAUDIO, &ra)<0)
{
perror("ioctl");
exit(1);
}
According to the kernel documentation for the cdrom driver, cdrom.txt, the format of the command is as follows:
CDROMREADAUDIO (struct cdrom_read_audio)
usage:
struct cdrom_read_audio ra;
ioctl(fd, CDROMREADAUDIO, &ra);
inputs:
cdrom_read_audio structure containing read start
point and length
outputs:
audio data, returned to buffer indicated by ra
error return:
EINVAL format not CDROM_MSF or CDROM_LBA
EINVAL nframes not in range [1 75]
ENXIO drive has no queue (probably means invalid fd)
ENOMEM out of memory
The format of the cdrom_read_audio struct can be found in cdrom.h:
/* This struct is used by the CDROMREADAUDIO ioctl */
struct cdrom_read_audio
{
union cdrom_addr addr; /* frame address */
__u8 addr_format; /* CDROM_LBA or CDROM_MSF */
int nframes; /* number of 2352-byte-frames to read at once */
__u8 __user *buf; /* frame buffer (size: nframes*2352 bytes) */
};
It uses a union cdrom_addr type, defined in the same file:
/* Address in either MSF or logical format */
union cdrom_addr
{
struct cdrom_msf0 msf;
int lba;
};
Here we have a choice - use MSF (Mintues-Seconds-Frames) or LBA (Logical Block Addressing). Since you're reading audio, you'll probably want MSF. struct cdrom_msf0 can also be found in the header file:
/* Address in MSF format */
struct cdrom_msf0
{
__u8 minute;
__u8 second;
__u8 frame;
};
With this research, we can write a simple test:
#include <sys/ioctl.h> //Provides ioctl()
#include <linux/cdrom.h> //Provides struct and #defines
#include <unistd.h> //Provides open() and close()
#include <sys/types.h> //Provides file-related #defines and functions
#include <sys/stat.h> //Ditto
#include <fcntl.h> //Ditto
#include <stdlib.h> //Provides malloc()
#include <string.h> //Provides memset()
#include <stdint.h> //Provides uint8_t, etc
#include <errno.h> //Provides errno
#include <stdio.h> //Provides printf(), fprintf()
int main()
{
int fd = open("/dev/cdrom", O_RDONLY | O_NONBLOCK);
if (errno != 0)
{
fprintf(stderr, "Error opening file: %u\n", errno);
return -1;
}
struct cdrom_msf0 time; //The start read time ...
time.minute = 2;
time.second = 45;
time.frame = 0;
union cdrom_addr address; //... in a union
address.msf = time;
struct cdrom_read_audio ra; //Our data object
ra.addr = address; //With the start time
ra.addr_format = CDROM_MSF; //We used MSF
ra.nframes = CD_FRAMES; //A second - 75 frames (the most we can read at a time anyway)
uint8_t* buff = malloc(CD_FRAMES * CD_FRAMESIZE_RAW); //Frames per second (75) * bytes per frame (2352)
memset(buff, 0, CD_FRAMES * CD_FRAMESIZE_RAW); //Make sure it's empty
ra.buf = buff; //Set our buffer in our object
if (ioctl(fd, CDROMREADAUDIO, &ra) != 0) //The ioctl call
{
fprintf(stderr, "Error giving ioctl command: %u\n", errno);
return -1;
}
for (int frame = 0; frame < CD_FRAMES; frame++) //A hexdump (could be a real use for the data)
{
printf("Frame %u:", frame);
for (int byte = 0; byte < CD_FRAMESIZE_RAW; byte++)
{
printf(" %.2X", buff[frame * CD_FRAMESIZE_RAW + byte]);
}
printf("\n");
}
close(fd); //Close our file
return 0; //And exit
}
Make sure you use an audio CD, or the ioctl call will throw EIO (with a CD-ROM, for example). In reality, you might write this data to file, or process it. Either way, you'd likely end up reading more than one second using a loop.
I have several files which I'm trying to compile using gcc in Ubuntu. I have vmware machine 16.04 ubuntu, which 64-bit computer. I have added the flags for 32bit compilation in the makefile. (-m32 flag).
This is the makefile:
all: clean binsem.a ut.a ph
FLAGS = -Wall -L./ -m32
ph: ph.c
gcc ${FLAGS} ph.c -lbinsem -lut -o ph
binsem.a:
gcc $(FLAGS) -c binsem.c
ar rcu libbinsem.a binsem.o
ranlib libbinsem.a
ut.a:
gcc $(FLAGS) -c ut.c
ar rcu libut.a ut.o
ranlib libut.a
clean:
rm -f *.o
rm -f a.out
rm -f *~
rm -f ph
rm -f *a
My attempts to compile the code were not successful, as I received the following error:
ph.c:126:12: warning: ‘main’ defined but not used [-Wunused-function]
/usr/lib/gcc/i686-linux-gnu/5/../../../i386-linux-gnu/crt1.o: In function `_start':
(.text+0x18): undefined reference to `main'
collect2: error: ld returned 1 exit status
Makefile:6: recipe for target 'ph' failed
make: *** [ph] Error 1
**I tried - **
Adding -c flags to the ph.c file in the make file. However it doesn't make much sense, since it has a main function. No success.
Adding sum -m32 flags in the makefile, in addition to what's already written. No Success.
The file "ph.c", is the following file -
#include <stdio.h>
#include <setjmp.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <stdint.h>
#include <sys/time.h>
#include <inttypes.h>
#include "binsem.h"
#include "ut.h"
#define LEFT (i+N-1)%N
#define RIGHT (i+1)%N
#define THINKING 0
#define HUNGRY 1
#define EATING 2
int N;
volatile int *phil_state;
sem_t *s;
sem_t mutex;
int *tid;
uint64_t get_wall_time() {
struct timeval time;
gettimeofday(&time, NULL);
uint64_t millis = (time.tv_sec * (uint64_t)1000) + (time.tv_usec / 1000);
return millis;
}
void think(int p) {
int i, factor;
volatile int j;
printf("Philosopher (%d) - time %" PRId64 " - is thinking\n",p, get_wall_time()); fflush (stdout);
factor = 1 + random()%5;
for (i = 0; i < 100000000*factor; i++){
j += (int) i*i;
}
printf("Philosopher (%d) - time %" PRId64 " - is hungry\n", p, get_wall_time()); fflush (stdout);
}
void eat(int p){
int i, factor;
volatile int j;
printf("Philosopher (%d) - time %" PRId64 " - is eating\n",p, get_wall_time()); fflush (stdout);
factor = 1 + random()%5;
for (i = 0; i < 100000000*factor; i++){
j += (int) i*i;
}
//printf("Philosopher (%d) - time %" PRId64 " - is thinking\n",p, get_wall_time()); fflush (stdout);
}
void test(int i){
if (phil_state[i] == HUNGRY &&
phil_state[LEFT] != EATING &&
phil_state[RIGHT] != EATING){
phil_state[i] = EATING;
binsem_up(&(s[i]));
}
}
void take_forks(int i){
binsem_down(&mutex);
phil_state[i] = HUNGRY;
test(i);
binsem_up(&mutex);
binsem_down(&(s[i]));
}
void put_forks(int i){
binsem_down(&mutex);
phil_state[i] = THINKING;
test(LEFT);
test(RIGHT);
binsem_up(&mutex);
}
void int_handler(int signo) {
long int duration;
int i;
for (i = 0; i < N; i++) {
duration = ut_get_vtime(tid[i]);
printf("Philosopher (%d) used the CPU %ld.%ld sec.\n",
i+1,duration/1000,duration%1000);
}
exit(0);
}
void philosopher(int i){
while (1){
think(i);
take_forks(i);
eat(i);
put_forks(i);
}
}
static int main(int argc, char *argv[])
{
int c;
if (argc != 2){
printf("Usage: %s N\n", argv[0]);
exit(1);
}
N = atoi(argv[1]);
if (N < 2){
printf("Usage: %s N (N >=2)\n", argv[0]);
exit(1);
}
ut_init(N);
s = (sem_t *)malloc (N * sizeof(sem_t));
phil_state = (int *) malloc (N * sizeof(int));
tid = (int *) malloc (N * sizeof(int));
for (c = 0; c < N ; c++){
phil_state[c] = THINKING;
binsem_init(&(s[c]), 0);
}
for (c = 0; c < N ; c++){
tid[c] = ut_spawn_thread(philosopher,c);
printf("Spawned thread #%d\n", tid[c]);
}
binsem_init(&mutex, 1);
signal(SIGINT,int_handler);
ut_start();
return 0; // avoid warnings
}
The makefile also tries to compile these files - ut.c, binsem.c
#include <stdlib.h>
#ifndef _UT_H
#define _UT_H
#include "ut.h"
#include <sys/time.h> // for itimerval
#include <unistd.h> // for alarm
#include <stdlib.h> // for malloc
#include <stdio.h> // for perror
#include <ucontext.h>
# include "ut.h"
#define MAX_TAB_SIZE 128 // the maximal threads table size.
#define MIN_TAB_SIZE 2 // the minimal threads table size.
#define SYS_ERR -1 // system-related failure code
#define TAB_FULL -2 // full threads table failure code
/*This type defines a single slot (entry) in the threads table. Each slot describes a single
thread. Note that we don't need to keep the thread state since every thread is always ready
or running. We also don't have to support adding/stopping thread dynamically, so we also don't
have to manage free slots.*/
typedef struct ut_slot {
ucontext_t uc;
unsigned long vtime; /* the CPU time (in milliseconds) consumed by this thread.*/
void (*func)(int); /* the function executed by the thread.*/
int arg; /* the function argument.*/
} ut_slot_t, *ut_slot;
static ut_slot threads; // pointer to thread table
static volatile int numThreads = 0; // number of threads in the table
static volatile int currentThread = 0; // current thread
static ucontext_t mainThread;
#define STACKSIZE 8192 // the thread stack size.
/* The TID (thread ID) type. TID of a thread is actually the index of the thread in the
threads table. */
typedef short int tid_t;
void handler(int signal){
alarm(1); //the alarm every second as demanded in the assignment
currentThread = (currentThread +1 ) % numThreads;
printf("in signal handler: switching from %d to %d\n", currentThread, currentThread - 1);
swapcontext(&threads[currentThread].uc, &threads[currentThread].uc); /*save current thread,
* load next thread*/
if (signal == SIGVTALRM){ // increment the time stats
threads[currentThread].vtime+=100;
} else if(signal==SIGALRM) {
if (swapcontext(&threads[currentThread - 1].uc, &threads[currentThread].uc) == -1) {
perror("could not do swapping");
exit(1);
}
}
}
int ut_init(int tab_size){
/// (###)
if(tab_size < MAX_TAB_SIZE) {
threads = (ut_slot) malloc(tab_size * sizeof(int(ut_slot_t)));
}
else{
threads = (ut_slot) malloc(MAX_TAB_SIZE * sizeof(int(ut_slot_t)));
}
if (!threads) {
return SYS_ERR;
}
return 0;
}
tid_t ut_spawn_thread(void (*func)(int), int arg){
/*uc[1].uc_link = &uc[0];
uc[1].uc_stack.ss_sp = st1; //stack fro thread 1
uc[1].uc_stack.ss_size = sizeof st1; //size of stack for therad
makecontext(&uc[1], (void(*)(void)) f, 1, 1); */
int thread_stack_size = STACKSIZE/8; //no need for 8K in size
if (numThreads>=TAB_FULL){ //(*)
return TAB_FULL;
}
if (getcontext(&threads[numThreads].uc)==-1){
return SYS_ERR;
}
ut_slot_t newThread;
threads[numThreads] = newThread;
threads[numThreads].uc.uc_link = &mainThread;
threads[numThreads].uc.uc_stack.ss_sp = (void* *)malloc(thread_stack_size);
if(threads[numThreads].uc.uc_stack.ss_sp==NULL){
return SYS_ERR;
}
makecontext(&threads[numThreads].uc,(void(*)(void))func,1,arg);
numThreads++;
return numThreads - 1;
}
int ut_start(void){
struct sigaction sigaction1;
int firstThread = 0; /*represents the current thread*/
struct itimerval itv;
/* set up vtimer for accounting */
itv.it_interval.tv_sec = 0;
itv.it_interval.tv_usec = 10000;
itv.it_value = itv.it_interval;
/* Initialize the data structures for SIGALRM handling. */
sigaction1.sa_flags = SA_RESTART; //restart instead of throwing exception
sigfillset(&sigaction1.sa_mask); // don't throw exception for additional signals
sigaction1.sa_handler = handler; // specify handler for the sigaction declared
if (sigaction(SIGVTALRM, &sigaction1, NULL) < 0)
return SYS_ERR;
/*START THE TIMER */
if (setitimer(ITIMER_VIRTUAL, &itv, NULL) < 0)
return SYS_ERR;
if (sigaction(SIGINT, &sigaction1, NULL) < 0)
return SYS_ERR;
/* Start running. */
alarm(1); //alarm every second
if(swapcontext(&threads[firstThread].uc,&threads[firstThread+1].uc)==-1){ //swap first time
return SYS_ERR;
}
return -1;
}
unsigned long ut_get_vtime(tid_t tid){
return threads[tid].vtime;
}
#endif
binsem.c
#ifndef _BIN_SEM_H
#define _BIN_SEM_H
#include "binsem.h"
#include <signal.h>
#include "atomic.h"
typedef unsigned long sem_t;
void binsem_init(sem_t *s, int init_val){
if(init_val == 1){
*s = 1;
}
else{
*s = 0;
}
}
void binsem_up(sem_t *s){
xchg(s,1); /*send the pointer of s, and the new value 1*/
}
int binsem_down(sem_t *s){
int flag = 0;
while (flag == 0){
xchg(s,0); /*try changing the value - down*/
if (*s != 0){ /*no success in changing*/
if (raise(SIGALRM)!=0){ /*raise returns 0 on success*/
return -1;
}
} else{
flag = 1;
return 0;
}
}
}
#endif
Any ideas?
You declare the main function to be static. That means it will have internal linkage, and not be exported. Therefore the linker will not be able to find it.
Remove the static modifier and that should work.
However there are also many other problems in your Makefile that will most likely lead to problems:
The target ph only depends on ph.c, not the libraries you want to link with. You need to add the libraries as dependencies as well (their full file-names).
You should also make the libraries depend on the object files used to create them, and rely on the implicit rules to build object files from source files.
Also note that for a library named A then the file-name needs to be libA.a, otherwise the linker will not be able to find it with the -l (lower-case L) option.
The error message is pretty clear:
(.text+0x18): undefined reference to `main'
In ph.c you have (probably accustomed from Java?):
static int main(int argc, char *argv[])
In C:
static ([CPPReference]: C keywords: static) means internal linkage (only valid in current translation unit (ph.o in our case)), so a static symbol won't be "seen" by the linker (loader)
Code linked to an application (not a dynamic library or shared object (.so: linked with -shared)), must explicitly define main, and that should be visible by the linker
The combination of the above 2, lead to what you're experiencing.
Remove the static and you'll be fine.
Note: There might be other errors in the Makefile.
I've currently started working on a PX4 autopilot and I was working throught one of the example applicaton and I tried to compile and upload the firmware to the Pixhawk.
The problem is that it failed to load giving me these errors:
make[2]: * [px4_simple_app.c.o] Error 1 make[1]: *
[/c/px4/Firmware/Build/px4fmu-v2_default.build//c/px4/Firmware/src/examples/px4_simple_app/module.pre.o]
Error 2 make[1]: Leaving directory
`/c/px4/Firmware/Build/px4fmu-v2_default.build' make: ***
[/c/px4/Firmware/Build/px4fmu-v2_default.build/firmware.px4] Error 2
I'm not sure what these mean, but inspecting the code it gave me this error in a certain line:
initialization makes integer from pointer without a cast
From this line:
int att_pub_fd = orb_advertise(ORB_ID(vehicle_attitude), &att);
and I'm not sure how I can fix this. Can someone give me some help?
This is the rest of the code:
/**
* #file px4_simple_app.c
* Minimal application example for PX4 autopilot
*/
#include <string.h>
#include <nuttx/config.h>
#include <unistd.h>
#include <stdio.h>
#include <poll.h>
#include <uORB/uORB.h>
#include <uORB/topics/sensor_combined.h>
#include <uORB/topics/vehicle_attitude.h>
__EXPORT int px4_simple_app_main(int argc, char *argv[]);
int px4_simple_app_main(int argc, char *argv[])
{
printf("Hello Sky!\n");
/* subscribe to sensor_combined topic */
int sensor_sub_fd = orb_subscribe(ORB_ID(sensor_combined));
orb_set_interval(sensor_sub_fd, 1000);
/* advertise attitude topic */
struct vehicle_attitude_s att;
memset(&att, 0, sizeof(att));
int att_pub_fd = orb_advertise(ORB_ID(vehicle_attitude), &att);
/* one could wait for multiple topics with this technique, just using one here */
struct pollfd fds[] = {
{ .fd = sensor_sub_fd, .events = POLLIN },
/* there could be more file descriptors here, in the form like:
* { .fd = other_sub_fd, .events = POLLIN },
*/
};
int error_counter = 0;
while (true) {
/* wait for sensor update of 1 file descriptor for 1000 ms (1 second) */
int poll_ret = poll(fds, 1, 1000);
/* handle the poll result */
if (poll_ret == 0) {
/* this means none of our providers is giving us data */
printf("[px4_simple_app] Got no data within a second\n");
} else if (poll_ret < 0) {
/* this is seriously bad - should be an emergency */
if (error_counter < 10 || error_counter % 50 == 0) {
/* use a counter to prevent flooding (and slowing us down) */
printf("[px4_simple_app] ERROR return value from poll(): %d\n"
, poll_ret);
}
error_counter++;
} else {
if (fds[0].revents & POLLIN) {
/* obtained data for the first file descriptor */
struct sensor_combined_s raw;
/* copy sensors raw data into local buffer */
orb_copy(ORB_ID(sensor_combined), sensor_sub_fd, &raw);
printf("[px4_simple_app] Accelerometer:\t%8.4f\t%8.4f\t%8.4f\n",
(double)raw.accelerometer_m_s2[0],
(double)raw.accelerometer_m_s2[1],
(double)raw.accelerometer_m_s2[2]);
/* set att and publish this information for other apps */
att.roll = raw.accelerometer_m_s2[0];
att.pitch = raw.accelerometer_m_s2[1];
att.yaw = raw.accelerometer_m_s2[2];
orb_publish(ORB_ID(vehicle_attitude), att_pub_fd, &att);
}
/* there could be more file descriptors here, in the form like:
* if (fds[1..n].revents & POLLIN) {}
*/
}
}
return 0;
}
the function
orb_advertise(ORB_ID(vehicle_attitude), &att)
returns a pointer and you are assigning it to an int.
Im not sure what you are trying to do but if its pointing to an integer than you need to dereference the pointer.