I am working on a project where I have to compare incoming data from a sensor. The main source code is in C++ along with a C source file, a .S file, and a .h file. When I am trying to link those files it shows an error and I don't have any clue as to what the error is. Any help regarding the problem will be very much appreciated.
My Makefile looks like:
all : main.cpp irq.c irq.h bootstrap.S
riscv32-unknown-elf-gcc -c irq.c bootstrap.S -march=rv32g -mabi=ilp32d -nostartfiles -Wl,--no-relax
riscv32-unknown-elf-g++ -c main.cpp -march=rv32g -mabi=ilp32d
riscv32-unknown-elf-g++ -o main main.o irq.o bootstrap.o -march=rv32g -mabi=ilp32d
dump-elf: all
riscv32-unknown-elf-readelf -a main
dump-code: all
riscv32-unknown-elf-objdump -D main
dump-comment: all
objdump -s --section .comment main
clean:
rm -f main`
main.cpp
#include "stdint.h"
extern "C"{
#include "irq.h"
}
#include<stdio.h>
#include<iostream>
using namespace std;
static volatile char * const TERMINAL_ADDR = (char * const)0x20000000;
static volatile char * const SENSOR_INPUT_ADDR = (char * const)0x50000000;
static volatile uint32_t * const SENSOR_SCALER_REG_ADDR = (uint32_t * const)0x50000080;
static volatile uint32_t * const SENSOR_FILTER_REG_ADDR = (uint32_t * const)0x50000084;
bool has_sensor_data = 0;
void sensor_irq_handler() {
has_sensor_data = 1;
}
void dump_sensor_data() {
while (!has_sensor_data) {
asm volatile ("wfi");
}
has_sensor_data = 0;
for (int i=0; i<64; ++i) {
*TERMINAL_ADDR = *(SENSOR_INPUT_ADDR + i) % 92 + 32;
}
*TERMINAL_ADDR = '\n';
}
int main() {
register_interrupt_handler(2, sensor_irq_handler);
*SENSOR_SCALER_REG_ADDR = 5;
*SENSOR_FILTER_REG_ADDR = 2;
for (int i=0; i<3; ++i)
dump_sensor_data();
return 0;
}
irq.c
https://github.com/agra-uni-bremen/riscv-vp/blob/master/sw/simple-sensor/irq.c
irq.h
https://github.com/agra-uni-bremen/riscv-vp/blob/master/sw/simple-sensor/irq.h
bootstrap.S
https://github.com/agra-uni-bremen/riscv-vp/blob/master/sw/simple-sensor/bootstrap.S
The output should be 64 random characters with interrupts.
The Error is:
/opt/riscv/lib/gcc/riscv32-unknown-elf/8.3.0/../../../../riscv32-unknown-elf/bin/ld: /tmp/cckjuDlw.o: in function `.L0 ':
(.text+0x0): multiple definition of `_start'; /opt/riscv/lib/gcc/riscv32-unknown-elf/8.3.0/../../../../riscv32-unknown-elf/lib/crt0.o:(.text+0x0): first defined here
You're using the -nostartfiles option, but in the wrong place.
You have it on a compilation step (-c option), while it belongs on linking.
-Wl, options are also only used when linking
Related
I have a program using OpenMP on C++ and I need it to port into Dll so I can call it from Python. It returns an array of double values, which calculated using a lot of for loops with openmp pragma. I was doubtful if it is going to work, so I started from a little test program that calculates Pi value in a loop with different precision values, then I would measure performance and ensure that OpenMP works properly that way. Plain (w/o Omp) implementation works fine from Python and C++, however Omp variant gives a runtime error in Python (exception: access violation writing 0x000000000000A6C8) and crashes without an error in C++. Also Omp variant works fine if it is not a Dll and just a regular executable. The Dll is made with a makefile. App that uses the Dll built into an executable with g++ with no flags (source code is in UnitMain.cpp). All the relevant code and a Makefile below (I didn't include some files and functions for brevity).
UPD: I tried Microsoft compiler and it works, also I tested a linux dynamic library on WSL/g++ and it also works. Looks like it is Windows gcc specific, I'll try another version of gcc (btw my current version is this):
Thread model: posix gcc version 8.1.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project)
UnitFunctions.cpp
#include "UnitFunctions.h"
#include <omp.h>
#include <stdio.h>
#include <string.h>
typedef long long int64_t;
double pi(int64_t n) {
double sum = 0.0;
int64_t sign = 1;
for (int64_t i = 0; i < n; ++i) {
sum += sign/(2.0*i+1.0);
sign *= -1;
}
return 4.0*sum;
}
void calcPiOmp(double* arr, int N) {
int64_t base = 10e5;
#pragma omp parallel for
for(int i = 0; i < N; ++i) {
arr[i] = pi(base+i);
}
}
UnitMain.cpp
#include <windows.h>
#include <iostream>
using namespace std;
struct DllHandle
{
DllHandle(const char * const filename)
: h(LoadLibrary(filename)) {}
~DllHandle() { if (h) FreeLibrary(h); }
const HINSTANCE Get() const { return h; }
private:
HINSTANCE h;
};
int main()
{
const DllHandle h("Functions.DLL");
if (!h.Get())
{
MessageBox(0,"Could not load DLL","UnitCallDll",MB_OK);
return 1;
}
typedef const void (*calcPiOmp_t) (double*, int);
const auto calcPiOmp = reinterpret_cast<calcPiOmp_t>(GetProcAddress(h.Get(), "calcPiOmp"));
double arr[80];
calcPiOmp(arr, 80);
cout << arr[0] << endl;
return 0;
}
Makefile
all: UnitEntryPoint.o UnitFunctions.o
g++ -m64 -fopenmp -s -o Functions.dll UnitEntryPoint.o UnitFunctions.o
UnitEntryPoint.o: UnitEntryPoint.cpp
g++ -m64 -fopenmp -c UnitEntryPoint.cpp
UnitFunctions.o: UnitFunctions.cpp
g++ -m64 -fopenmp -c UnitFunctions.cpp
A Python script
import numpy as np
import ctypes as ct
cpp_fun = ct.CDLL('./Functions.dll')
cpp_fun.calcPiNaive.argtypes = [np.ctypeslib.ndpointer(), ct.c_int]
cpp_fun.calcPiOmp.argtypes = [np.ctypeslib.ndpointer(), ct.c_int]
arrOmp = np.zeros(N).astype('float64')
cpp_fun.calcPiOmp(arrOmp, N)
I faced a little trouble. I'm not sure if I can understand it.
So, I have some code. And I'm trying to add #pragma loop(hint_parallel(8)) statement for a few loops in the code.
When I compile that using necessary compilation options which are actually like this:
gcc -w -funroll-loops -O2 -fno-inline -fipa-pta -msse2
-funsafe-math-optimizations -ftree-vectorizer-verbose=1 -fopt-info-optimized=logs/optOpt.txt -shared -fPIC singleThread.cpp
I get segmentation fault.
fish: './a.out' terminated by signal SIGSEGV (Address boundary error)
The point is that I have no idea why it is. I suspected that it could be a problem with a constant that is used in these loops. But I don't think that this is related. if I just compile this code using -O0 optimisation it works fine (because complier doesn't vectorise something I guess).
Could you please take a look on the code below and suggest me in which direction I should check.
Thanks.
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <random>
#include <cstdio>
#include <set>
#include <fstream>
#include <cstdint>
#include <climits>
using namespace std;
const int STRING_HASH_SIZE = 32;
int convert(vector<string> &inputVector, const char **outputArray);
void printCollisions(const char **charArray, int size);
void printArray(const char **arrayToPrint, int size);
int getHashCode(const char *characters, unsigned long size);
string getRandomString();
void writeFileIfNeeded(vector<string> &vector, bool needToWrite);
vector<string> generateStringsVector(int size, bool isNeedToWriteFile);
/**
* main method is present to test these native code.
* to perform some external operation we should use another method.
* #return
*/
int main() {
/**
* The constant represents number of strings that will be generated
* in the string vector generation.
*/
const int STRING_NUMBERS = 100000;
vector<string> inputVector = generateStringsVector(STRING_NUMBERS, false);
#pragma pack 8
const char *charArray[inputVector.size()];
int hashResult = convert(inputVector, charArray);
if (hashResult != 0) {
return 0;
}
printCollisions(charArray, STRING_NUMBERS);
}
/**
* Converts an input vector to char array.
* Getting a hash of
* Returns 0 if conversion from vector to array has been successfully performed.
* #param inputVector [ input array reference ]
* #param outputArray [ a char array that would contain char sequences from vector ]
* #return [ hash sum (int)]
*/
int convert(vector<string> &inputVector, const char **outputArray) {
int hashSum = 0;
#pragma loop(hint_parallel(8))
for (int i = 0; i < inputVector.size(); i++) {
outputArray[i] = inputVector[i].c_str();
}
#pragma loop(hint_parallel(8))
for (auto &i : inputVector) {
hashSum += getHashCode(i.c_str(), i.length());
}
int stringHashSize = STRING_HASH_SIZE;
#pragma loop(hint_parallel(8))
for (int i = 0; i < inputVector.size(); i++) {
hashSum -= getHashCode(outputArray[i], stringHashSize);
}
if (hashSum != 0) {
cout << "\nConversion isn't succeeded, hash = " << hashSum << endl;
} else {
cout << "\nConversion succeeded" << endl;
}
return hashSum;
}
/**
* Prints count and percentage of collisions in array hash codes
* #param charArray
* #param size
*/
void printCollisions(const char **charArray, int size) {
set<int> setOfHashes;
int stringHashSize = STRING_HASH_SIZE;
#pragma loop(hint_parallel(8))
for (int i = 0; i < size; i++) {
setOfHashes.insert(getHashCode(charArray[i], stringHashSize));
}
unsigned long collisions = size - setOfHashes.size();
cout << collisions << "/" << size << " " << 100.0 * collisions / size << "% of collisions";
}
/**
* Prints input char array
* #param arrayToPrint
*/
void printArray(const char **arrayToPrint, int size) {
cout << "\nPrinted array size = " << size << endl;
for (int i = 0; i < size; i++) {
cout << arrayToPrint[i] << ":" << getHashCode(arrayToPrint[i], STRING_HASH_SIZE) << endl;
}
}
/**
*
* #param characters
* #return
*/
int getHashCode(const char *characters, unsigned long size) {
int hash = 0;
#pragma loop(hint_parallel(8))
for (int i = 0; i < size; i++) {
hash = (31 + hash) * (characters[i]);
}
return hash;
}
/**
* Get a random String from alphabetical char sequence.
* #return a randomized string according to an alphabet.
*/
string getRandomString() {
string str("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
random_device rd;
mt19937 generator(rd());
shuffle(str.begin(), str.end(), generator);
return str.substr(0, STRING_HASH_SIZE);
}
/**
* Generates a vector with random strings
* #param size - an int value that will be used as size of a generated vector
* #return reference to generated vector.
*/
vector<string> generateStringsVector(int size, bool isNeedToWriteFile) {
vector<string> charArray;
#pragma loop(hint_parallel(8))
for (int i = 0; i < size; i++) {
string str = getRandomString();
charArray.push_back(str);
}
writeFileIfNeeded(charArray, isNeedToWriteFile);
return charArray;
}
/**
* Writes file with name according to vector size (e.g. 100000.csv)
* if needToWrite is true
* #param vector
* #param needToWrite
*/
void writeFileIfNeeded(vector<string> &vector, bool needToWrite) {
if (needToWrite) {
ofstream csvFile;
string filename = to_string(vector.size()) + ".csv";
csvFile.open(filename, fstream::out);
for (const auto &i : vector) {
csvFile << i << "\n";
}
csvFile.close();
}
}
What is causing the segmentation fault is the way you compile your code and not the pragmas (which don't have any effect in gcc anyway, see below):
gcc -w -funroll-loops -O2 -fno-inline -fipa-pta -msse2
-funsafe-math-optimizations -ftree-vectorizer-verbose=1 -fopt-info-optimized=logs/optOpt.txt -shared -fPIC singleThread.cpp
By using -shared -fPIC you are creating a DSO (dynamic shared object). If you try to execute this file, you'll get an invalid PC (program counter) and your program will crash immediately. You must compile your code without -shared -fPIC (and use -pie -fPIE if you need a position-independent executable).
Also, for compiling C++ code you should normally use g++ instead of gcc.
The given pragmas should not have any effect on your code, as these ones are only understood by Microsoft Visual Studio. Add -Wall to your compile options and gcc will show you the respective warnings.
In any case, you should get rid of vendor-specific pragmas and use standardized solutions like OpenMP instead (compile with -fopenmp). That way, you are a step closer to writing compiler-independent code.
As for the parallelized loops, you should make sure you don't run into race conditions or other synchronization failures. For example, to compute a sum, #pragma omp parallel for reduction(+: sum) is your friend in OpenMP (reference sheet).
Disclaimer: I have used gcc 7.3.0 on x86_64 (CentOS Linux).
I want to compile a simple project with several additional classes in cpp. Unfortunately, when avr-g++ is called with avr-g++.exe -o stepper.elf src/add_functions.o src/ASF/common/services/hugemem/avr8/avr8_hugemem.o src/ASF/common/services/sleepmgr/xmega/sleepmgr.o src/ASF/common/services/spi/xmega_spi/spi_master.o src/ASF/xmega/drivers/dma/dma.o src/ASF/xmega/drivers/spi/spi.o src/gpio_control.o src/spi_control.o src/usart_control.o src/ASF/common/boards/user_board/init.o src/ASF/common/services/clock/xmega/sysclk.o src/ASF/common/services/ioport/xmega/ioport_compat.o src/ASF/common/services/serial/usart_serial.o src/ASF/xmega/drivers/cpu/ccp.o src/ASF/xmega/drivers/usart/usart.o src/main.o -Wl,-Map="stepper.map" -Wl,--start-group -Wl,-lm -Wl,--end-group -Wl,--gc-sections -mmcu=atxmega16a4 for the following code:
#include <asf.h>
#include <string.h>
#include "usart.h"
class usart_controller
{
//variables
public:
protected:
private:
static usart_rs232_options_t USART_options;
USART_t *usart;
//functions
public:
usart_controller(USART_t *usart, uint32_t baudrate, USART_CHSIZE_t charlength, USART_PMODE_t paritybyte, bool stopbit);
~usart_controller();
void send_data(uint32_t *data32, size_t data32_size);
uint8_t * rec_data();
protected:
private:
usart_controller( const usart_controller &c );
usart_controller& operator=( const usart_controller &c );
}; //usart_controller
#include "usart_control.h"
// default constructor
usart_controller::usart_controller(USART_t *usart, uint32_t baudrate, USART_CHSIZE_t charlength, USART_PMODE_t paritybyte, bool stopbit)
{
this->USART_options.baudrate = baudrate;
//this->USART_SERIAL_OPTIONS.charlength = charlength;
//this->USART_SERIAL_OPTIONS.paritytype = paritybyte;
//this->USART_SERIAL_OPTIONS.stopbits = stopbit;
this->usart = usart;
//usart_init_rs232(usart, &(this->USART_SERIAL_OPTIONS));
} //usart_controller
// default destructor
usart_controller::~usart_controller()
{
} //~usart_controller
void usart_controller::send_data(uint32_t * data32, size_t data32_size)
{
size_t data_size = 4 * data32_size;
uint8_t *data = new uint8_t[data32_size * 4];
for(unsigned int i = 0; i < data32_size; i++)
{
for(int j = 0; j < 4; j++)
{
data[i*j+j] = (data32[i] << (j*8));
}
}
usart_serial_write_packet(this->usart, data, data_size * sizeof(uint8_t));
delete[] data;
}
uint8_t * usart_controller::rec_data()
{
uint8_t * data = new uint8_t[32];
usart_serial_read_packet(this->usart, data, 32*sizeof(uint8_t));
return data;
}
I get the error " error: undefined reference to usart_controller::USART_options'" for the commandthis->USART_options.baudrate = baudrate;`. When I compile it alone, everything is going fine, and I get a valid object file. When trying to link it afterwards I get the error shown above. Why? Did I miss something? I am already linking everything I need.
In c++, it's not enough to declare a static data member in a class. It also has to be defined somewhere to allocate memory for it. If you add
usart_rs232_options_t usart_controller::USART_options;
somewhere in your source file (e.g. right after the class definition), it will be linked just fine :)
PS: Atmel? Have fun and be careful with that little devil! :)
I am having some trouble with my school project. I think that it may be an error with my use of pointers but I am not sure why I am getting this error. This code is incomplete but I am trying to test it along the way. Do you have any idea why I am getting this error and what does it mean? Thanks!
Error from Cygwin Terminal
-bash-3.2$ make clean
rm -rf *.o simulate
-bash-3.2$ make simulate
g++ -c -g Main.cpp
g++ -c -g Maze.cpp
g++ Main.o Maze.o -o simulate
/usr/bin/ld: Dwarf Error: found dwarf version '4', this reader only handles version 2 information.
Maze.o: In function `Maze::createMaze(char*)':
Maze.cpp:(.text+0x49): undefined reference to `Node::Node(char)'
collect2: error: ld returned 1 exit status
make: *** [simulate] Error 1
Main.cpp
#include <iostream>
#include <fstream>
#include <string>
#include "Maze.h"
using namespace std;
int main()
{
int array_size = 1024;
char * mazeArray = new char[array_size];
int position = 0;
string mazeName;
Maze Maze1;
cout << "Enter the name of the maze file: ";
getline(cin, mazeName);
ifstream fin(mazeName.c_str());
//File opened successfully
if(fin.is_open())
{
while(!fin.eof() && position < array_size)
{
fin.get(mazeArray[position]); //reading one character from file to mazeArray
position++;
}
mazeArray[position-1] = '\0'; //placing character mazeArray terminating character
for(int i = 0; mazeArray[i] != '\0'; i++){
if(isspace(mazeArray[i]))
mazeArray[i] = mazeArray[i+1];
}
cout << "Displaying mazeArray..." << endl << endl;
//this loop display all the charaters in mazeArray till \0
for(int i = 0; mazeArray[i] != '\0'; i++)
{
cout << mazeArray[i];
}
cout << endl;
Maze1.createMaze(mazeArray);
}
else //file could not be opened
{
cout << "File could not be opened." << endl;
}
return 0;
}
Maze.h
#ifndef MAZE_H
#define MAZE_H
#include <string>
#include <sstream>
#include <vector>
#include "Node.h"
using namespace std;
class Maze
{
public:
void createMaze(char*);
void availablePaths();
void displayPath();
void moveNorth();
void moveSouth();
void moveEast();
void moveWest();
int getroomCount();
char getpathHistory();
char getcurrentRoom();
private:
int roomCount;
char pathHistory[];
Node* currentRoom;
Node* nodeArray[12];
struct isPath;
vector<Node*> nodeVector;
};
#endif
Maze.cpp
#include <iostream>
#include <string>
#include "Maze.h"
using namespace std;
Node* Node1;
void Maze::createMaze(char *inFile){
int count = 0;
//Creates Nodes for Maze
for(int ii = 0; ii <= 12; ii++){
Node1 = new Node(inFile[count]);
nodeVector.push_back(Node1);
count = count + 5;
//If there is not another node break out of the for loop.
if(inFile[count] == '\0'){
break;
}
}
}
void Maze::availablePaths(){
}
void Maze::displayPath(){
}
void Maze::moveNorth(){
}
void Maze::moveSouth(){
}
void Maze::moveEast(){
}
void Maze::moveWest(){
}
int Maze::getroomCount(){
}
char Maze::getpathHistory(){
}
char Maze::getcurrentRoom(){
}
Node.h
#ifndef NODE_H
#define NODE_H
#include <string>
#include <map>
#include <sstream>
using namespace std;
class Node
{
public:
Node(char);
void setNodeName(char);
void attachNewNode(Node, int);
Node *getAttachedNode(int);
private:
char name; // Title that is displayed above the menu.
Node *attachedNodes[4];
};
#endif
Node.cpp
#include <iostream>
#include <string>
#include <vector>
#include "Node.h"
using namespace std;
Node::Node(char name) : name(name) {
}
void Node::setNodeName(char tempName){
name = tempName;
}
void Node::attachNewNode(Node temp, int direction){
attachedNodes[direction] = temp;
}
Node Node::getAttachedNode(int direction){
return attachedNodes[direction];
}
makefile
#!/bin/bash
#file:makefile
CC = g++
CFLAGS = -c -g
simulate: Main.o Maze.o
$(CC) Main.o Maze.o -o simulate
Main.o: Main.cpp Maze.h
$(CC) $(CFLAGS) Main.cpp
Maze.o: Maze.cpp Menu.h Node.h
$(CC) $(CFLAGS) Maze.cpp
Node.o: Node.cpp Node.h
$(CC) $(CFLAGS) Node.cpp
clean:
rm -rf *.o simulate
The problem is not in your code, per se.
One problem is that your linking command is failing because you are not linking all your object files. You need to link Main.o, Maze.o and Node.o to create the executable:
g++ Main.o Maze.o Node.o -o simulate
Another problem is that your compiler is newer than your linker. The compiler is generating debugging information using Dwarf version 4, but your linker (/usr/bin/ld) only understands Dwarf version 2.
/usr/bin/ld: Dwarf Error: found dwarf version '4', this reader only handles
version 2 information.
You need to update your linker to a newer version compatible with the compiler you are using.
Or, as janneb suggests in a comment, you can use -gdwarf-2 in both the compilation and link lines. In the makefile:
CFLAGS = -c -gdwarf-2
FILES.cpp = Main.cpp Maze.cpp Node.cpp
FILES.o = $(FILES.cpp:.cpp=.o}
simulate: $(FILES.o)
$(CC) $(CFLAGS) $(FILES.o) -o $#
(There should be few parts of command lines in a makefile that are not macro invocations; then you can change everything more easily.)
You will need to remove the Dwarf-4 object files and recompile to avoid the error/warning.
You can simply fix this by:
export CFLAGS='-gdwarf-2 -gstrict-dwarf'
Then, remake your project.
I have simple class ina header file:
> cat Algorithms.hh
#ifndef Algorithms_hh
#define Algorithms_hh
#include<vector>
class Algorithms
{
public:
Algorithms();
void BubbleSort();
std::vector<int> myarray;
};
#endif
Then a corresponding c file:
> cat Algorithms.cc
#include <iostream>
#include <vector>
#include "Algorithms.hh"
Algorithms::Algorithms()
{
myarray.push_back(0);
}
void Algorithms::BubbleSort()
{
int i, j, flag = 1; // set flag to 1 to start first pass
int temp; // holding variable
int numLength = myarray.size();
for(i = 1; (i <= numLength) && flag; i++)
{
flag = 0;
for (j=0; j < (numLength -1); j++)
{
if (myarray[j+1] > myarray[j]) // ascending order simply changes to <
{
temp = myarray[j]; // swap elements
myarray[j] = myarray[j+1];
myarray[j+1] = temp;
flag = 1; // indicates that a swap occurred.
}
}
}
}
>
And then the main function:
> cat algo2.cc
#include <iostream>
#include <vector>
#include "Algorithms.hh"
using namespace std;
int main(int argc,char **argv)
{
Algorithms *arr=new Algorithms();
arr->myarray.push_back(1);
arr->myarray.push_back(2);
arr->myarray.push_back(100);
return 0;
}
>
When i compile the main:
I get the below error:
> CC algo2.cc
Undefined first referenced
symbol in file
Algorithms::Algorithms() algo2.o
ld: fatal: Symbol referencing errors. No output written to a.out
Can anyone tell me where i am wrong?
This is a linker error, the linker is telling you it can't find the definition of constructor of class Algorithms. You should compile with:
CC Algorithms.cc algo2.cc
You can identify it's a linker error because of the ld: in front of the error.
And of course as stated by Kerrek SB you need to declare your constructor without the Algorithms:: in front of it...
You've just forgotten to include both .cc files into compiling:
cc algo2.cc Algorithms.cc
If you include header file with declarations, like
#include "Algorithms.hh"
you should also provide implementation, definition in .c, or .lib. or load library with definition dynamically. In your case your library is Algorithms.cc, so just add it into compilation stage, and then both temporary object files
Algo2.a + Algorithms.a
will go to
a.out