I'm writing a program to get myself acquainted with OpenSSL, libncurses, and UDP networking. I decided to work with OpenSSL's SHA256 to become familiar with industry encryption standards, but I'm having issues with getting it working. I've isolated the error to the linking of OpenSSL with the compiled program. I'm working on Ubuntu 12.10, 64 bit. I have the package libssl-dev installed.
Take, for instance, the C++ main.cpp:
#include <iostream>
#include <sstream>
#include <string>
#include <iomanip>
using namespace std;
#include <openssl/sha.h>
string sha256(const string str)
{
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, str.c_str(), str.size());
SHA256_Final(hash, &sha256);
stringstream ss;
for(int i = 0; i < SHA256_DIGEST_LENGTH; i++)
{
ss << hex << setw(2) << setfill('0') << (int)hash[i];
}
return ss.str();
}
int main()
{
cout << sha256("test") << endl;
cout << sha256("test2") << endl;
return 0;
}
I'm using the SHA256() function found here as a wrapper for OpenSSL's SHA256 functionality.
When I attempt to compile with the following g++ arguments, I receive the following error:
millinon#myhost:~/Programming/sha256$ g++ -lssl -lcrypto -o main main.cpp
/tmp/ccYqwPUC.o: In function `sha256(std::string)':
main.cpp:(.text+0x38): undefined reference to `SHA256_Init'
main.cpp:(.text+0x71): undefined reference to `SHA256_Update'
main.cpp:(.text+0x87): undefined reference to `SHA256_Final'
collect2: error: ld returned 1 exit status
So, GCC clearly recognizes OpenSSL's defined functions and types, but ld is failing to find the function symbols referred to in sha.h.
Do I need to manually point to a specific shared object or directory?
Thanks!
You make a very common beginners mistake... Putting the libraries you link with in the wrong place on the command line when you build.
Dependencies are reversed on the command line, so something that depends on something else should actually be put before what it depends on on the command line.
In your example, you have a source file main.cpp that depends on some set of libraries, then the source file should be before the libraries it depend on:
$ g++ -o main main.cpp -lssl -lcrypto
To be safe, always put libraries last, after any source or object files listed on the command line.
This works fine on my system, but you might try:
extern "C" {
#include <openssl/sha.h>
}
which tells g++ that all the stuff in openssl/sha.h is declared as "C" functions.
BTW, how old is your OpenSSL?
Related
So I installed OpenSSL directly following the instructions in the install.txt file you get when cloning the git repository. It installed it seemingly witout issues and is located in C:/Program Files/OpenSSL and C:/Program Files(x86)/OpenSSL. Inside each of those there are 4 folders: bin, html, include, lib.
In VSCode I'm using the code runner extension with the following command:
g++ -I "C:/Users/Batres/vcpkg/installed/x86-windows/include" "C:/Program Files/OpenSSL/include" simple_functions.cpp -o simple_functions
the "C:/Users/Batres/vcpkg/installed/x86-windows/include" is a different library called XTensor, which works completely fine as I have tested the code without OpenSSL and it outputs the correct results with no problem. This is the code I'm using, although I doubt it's relevant since it seems to be a complier issue.
#include <cmath>
#include <iomanip>
#include <cstddef>
#include "xtensor.hpp"
#include <functional>
#include <string>
#include <typeinfo>
#include <vector>
#include <regex>
#include <array>
#include <algorithm>
#include <openssl/sha.h>
#include <openssl/evp.h>
/*
def hash_string(string):
# Truncating at 16 bytes for cleanliness
hasher = hashlib.sha256(string.encode())
return hasher.hexdigest()[:16]
*/
std::string hash_string(std::string string) {
// Truncating at 16 bytes for cleanliness
std::array<unsigned char, SHA256_DIGEST_LENGTH> hash;
std::array<unsigned char, SHA256_DIGEST_LENGTH>::iterator it;
EVP_MD_CTX* ctx = EVP_MD_CTX_new();
EVP_DigestInit_ex(ctx, EVP_sha256(), NULL);
EVP_DigestUpdate(ctx, string.c_str(), string.size());
EVP_DigestFinal_ex(ctx, hash.data(), NULL);
// Convert the hash to a hexadecimal string
std::stringstream ss;
for (it = hash.begin(); it != hash.end(); it++) {
ss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(*it);
}
return ss.str().substr(0, 16);
}
int main(){
double a = gen_choose(2,5);
std::string input = "Hello, world!";
std::string output = hash_string(input);
std::cout << std::setprecision(16) << output << std::endl;
return 0;
}
Ignore all the other #includes, they are for different functions that work with no issue. As you can probably see I have some python code commented above my C++ code. Thats simply because it's a function I tried transalting using ChatGPT, but that's not relevant to the error.
This is the line for C++ settings in code-runner.executorMap:
"cpp": "cd $dir && g++ -I \"C:/Users/Batres/vcpkg/installed/x86-windows/include\" \"C:/Program Files/OpenSSL/lib\" $fileName -o $fileNameWithoutExt -lssl && $dir$fileNameWithoutExt"
My compiler is mingw and I'm on Windows 11. I also don't have any antivirus aside from Windows Defender and I've added the library to the exceptions list as well as ld.exe.
I have also tried these commands, all yeilding the same error. I have also tried running all the same commands through a terminal with admin priviliges and it gives the same error. I even copied the folder to a different directory inside my /Documents/ folder and it still didn't help.g++ -I "C:/Users/Batres/vcpkg/installed/x86-windows/include" "C:/Program Files (x86)/OpenSSL/include" simple_functions.cpp -o simple_functions
and
g++ -I "C:/Users/Batres/vcpkg/installed/x86-windows/include" -L "C:/Program Files/OpenSSL/lib" simple_functions.cpp -o simple_functions -lssl
This last one returns a different error. Insted of being acces denied it seems like none of the functions or variables that I call inside my code are recognised, so this is the type of error: undefined reference to 'EVP_MD_CTX_new', or any other functions or variables I call.
The weird thing is that even though it says access denied when compliling, Intellisense can acess the files just fine, I can right click on the functions and "Go to Definition" and it takes me to my C:/Program Files/OpenSSL/include/openssl/ folder.
If anyone knows how to fix the error I would be very thankful.
So I'm trying to write a bit of code to work with sudoku puzzles, and I keep getting errors when I try to compile, and each time i compile it deletes the driver.
heres the code for the driver:
/*
* Jared C
* C++ Project
*/
#include <iostream>
#include "SudokuBoard.h"
using namespace std;
int main()
{
SudokuBoard board("sudoku.txt");
board.printBoard();
}
And here's the header file
/*
* Jared C
* SudokuBoard.h
*/
#ifndef __SUDOKUBOARD_H_INCLUDED__
#define __SUDOKUBOARD_H_INCLUDED__
#include <iostream>
#include <string>
class SudokuBoard
{
private:
int content[9][9];
public:
SudokuBoard(std::string filename);
void printBoard();
int getNumAt(int, int);
void setNumAt(int, int, int);
};
#endif
And finally the Sudoku Board.cpp
/*
* Jared C
* SudokuBoard.cpp
*/
#include <iostream>
#include <fstream>
#include "stdlib.h"
#include "SudokuBoard.h"
using namespace std;
SudokuBoard::SudokuBoard(string filename)
{
string output;
string line;
int count = 0;
ifstream file;
file.open(filename.c_str());
if (file.is_open())
{
while (getline (file, line))
{
output += line;
}
file.close();
}
else cout<< "unable to open file" << endl;
for(int y = 0; y < 9; y++)
{
for(int x = 0; x < 9; x++)
{
content[x][y] = atoi(output.substr(count,1).c_str());
count ++;
}
}
}
void SudokuBoard::printBoard()
{
string output = "\n";
for(int y = 0; y < 9; y++)
{
if(y%3==0)
{
output += '\n';
}
for(int x = 0; x < 9; x++)
{
if(x%3==0)
{
output += " ";
}
output += content[x][y];
output += "\n";
}
}
cout<<output<<endl;
}
int SudokuBoard::getNumAt(int x, int y)
{
return content[x][y];
}
void SudokuBoard::setNumAt(int x, int y, int value)
{
content[x][y] = value;
}
When i call gcc -c SudokuBoard.cpp I get the SudokuBoard.o file just fine, but when I then call 'gcc -o Driver.cpp SudokuBoard.o' I get a huge wall of error messages, heres a sample of them:
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 0 has invalid symbol index 11
SudokuBoard.cpp:(.text+0x34): undefined reference to `std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string()'
SudokuBoard.cpp:(.text+0x43): undefined reference to `std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string()'
And it deletes Driver.cpp Any idea what I'm doing wrong?
Your command line is incorrect:
gcc -o Driver.cpp SudokuBoard.o
Instructs gcc to link the object file SudokuBoard.o as an executable file named Driver.cpp. No surprise that it first erases the destination file.
Furthermore, you do not specify the runtime library to link with and gcc does not default to C++: this explains the error message.
You should instead write:
g++ -o Sudoku Driver.o SudokuBoard.o
Use g++ to compile C++ code, not the common C-oriented gcc.
g++ invokes gcc for compilation and linking with the right options for C++.
In short, it's a good idea to use a C++ compiler for C++ source code, a Fortran compiler for Fortran source code, and so on.
Also, for the issue of “And it deletes Driver.cpp”, simply don't specify that source file as an output file.
The problem is that the -o option with gcc is used for specifying the output file. If you write
gcc -o Driver.cpp SudokuBoard.o
you tell the compiler to create an executable file named Driver.cpp out of the object file SudokuBoard.o. But as SudokuBoard.o has no main method, this will fail, therefore the error messages.
Try
gcc -c SudokuBoard.cpp
gcc -c Driver.cpp
gcc -o Sudoku SudokuBoard.o Driver.o
instead.
The compiler is telling you it can't find the implementation for std::basic_string<...>.
You need to tell the compiler how to find the compiled code for std::basic_string<...>. Much how with your own code, if you tried to build an executable out of just Driver.cpp the compiler would complain about missing SudokuBoard references until you told it about SudokuBoard.o.
In this case you need to tell the compiler about the C++ standard library. This library are usually shipped with your distribution. On Windows in the form of dll files, on OS X dylib files and on Linux so files. Conceptually they are similar, many bags of .o files all together. Either way, you tell the linker to link to the C++ standard library.
gcc calls the C++ standard library libstdc++, so your command would be something like: gcc -o Driver Driver.cpp SudokuBoard.o -lstdc++.
In my Homebrew installation my libraries are compiled with clang, whereas I would like to, for performance reasons, compile my scientific code with gcc. In order to understand this problem better, I have created a minimal test:
// FILE print.cxx
#include <string>
#include <iostream>
void print_message(const std::string& message)
{
std::cout << message << std::endl;
}
// FILE test.cxx
#include <string>
void print_message(const std::string&);
int main()
{
std::string message = "Hello World!";
print_message(message);
return 0;
}
This code I compile with:
// SCRIPT compile.sh
clang++ -stdlib=libstdc++ -c print.cxx
g++ test.cxx print.o
The example that I have added works, but is it possible to make it work with libraries that are compiled without the -stdlib=libstdc++ flag and instead use the libc++?
I'm writing a program to get myself acquainted with OpenSSL, libncurses, and UDP networking. I decided to work with OpenSSL's SHA256 to become familiar with industry encryption standards, but I'm having issues with getting it working. I've isolated the error to the linking of OpenSSL with the compiled program. I'm working on Ubuntu 12.10, 64 bit. I have the package libssl-dev installed.
Take, for instance, the C++ main.cpp:
#include <iostream>
#include <sstream>
#include <string>
#include <iomanip>
using namespace std;
#include <openssl/sha.h>
string sha256(const string str)
{
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, str.c_str(), str.size());
SHA256_Final(hash, &sha256);
stringstream ss;
for(int i = 0; i < SHA256_DIGEST_LENGTH; i++)
{
ss << hex << setw(2) << setfill('0') << (int)hash[i];
}
return ss.str();
}
int main()
{
cout << sha256("test") << endl;
cout << sha256("test2") << endl;
return 0;
}
I'm using the SHA256() function found here as a wrapper for OpenSSL's SHA256 functionality.
When I attempt to compile with the following g++ arguments, I receive the following error:
millinon#myhost:~/Programming/sha256$ g++ -lssl -lcrypto -o main main.cpp
/tmp/ccYqwPUC.o: In function `sha256(std::string)':
main.cpp:(.text+0x38): undefined reference to `SHA256_Init'
main.cpp:(.text+0x71): undefined reference to `SHA256_Update'
main.cpp:(.text+0x87): undefined reference to `SHA256_Final'
collect2: error: ld returned 1 exit status
So, GCC clearly recognizes OpenSSL's defined functions and types, but ld is failing to find the function symbols referred to in sha.h.
Do I need to manually point to a specific shared object or directory?
Thanks!
You make a very common beginners mistake... Putting the libraries you link with in the wrong place on the command line when you build.
Dependencies are reversed on the command line, so something that depends on something else should actually be put before what it depends on on the command line.
In your example, you have a source file main.cpp that depends on some set of libraries, then the source file should be before the libraries it depend on:
$ g++ -o main main.cpp -lssl -lcrypto
To be safe, always put libraries last, after any source or object files listed on the command line.
This works fine on my system, but you might try:
extern "C" {
#include <openssl/sha.h>
}
which tells g++ that all the stuff in openssl/sha.h is declared as "C" functions.
BTW, how old is your OpenSSL?
I'm on Linux, the question is concerning shared objects of C++ classes.
The problem comes when my shared objects try to use resources linked into the main executable. I have the following codes:
loader.cpp:
#include <dlfcn.h>
#include <iostream>
#include "CommonInfo.h"
using namespace std;
int main(int argc, char** argv) {
for(int i=1; i<argc; ++i) {
string pth = "./";
pth.append(argv[i]);
void* dh = dlopen(pth.c_str(), RTLD_NOW);
if(dh==NULL) {
cerr << dlerror() << endl;
return 1;
}
CommonInfo::GetInfoFunc getInfo = (CommonInfo::GetInfoFunc)(dlsym(dh,"getInfo"));
if(getInfo==NULL) {
cerr << dlerror() << endl;
return 1;
}
CommonInfo* info = getInfo();
cout << "INFO: " << info->getX() << endl;
delete info;
}
return 0;
}
CommonInfo.h:
#include <string>
class CommonInfo {
public:
typedef CommonInfo* (*GetInfoFunc)();
private:
std::string x;
public:
CommonInfo(const std::string& nx);
std::string getX() const;
};
EDIT:
I accidentaly forgot to ctrl-c + ctrl-v the source of CommonInfo.cpp here. Of course, it is there during compilation, so CommonInfo.cpp:
#include "CommonInfo.h"
CommonInfo::CommonInfo(const std::string& nx) : x(nx) {
}
std::string CommonInfo::getX() const {
return x;
}
A Plugin.h header:
#include "CommonInfo.h"
extern "C" CommonInfo* getInfo();
A very simple Plugin.cpp:
#include <iostream>
#include "Plugin.h"
#include "CommonInfo.h"
using namespace std;
CommonInfo* getInfo() {
return new CommonInfo("I'm a cat!");
}
Compiling is done with:
g++ -rdynamic -ldl -Werror CommonInfo.cpp loader.cpp -o loader
g++ -shared -fPIC -Werror Plugin.cpp -o Plugin.so
Running:
./loader Plugin.so
And there goes the error:
./loader: symbol lookup error: ./Plugin.so: undefined symbol: _ZN10CommonInfoC1ERKSs
Indeed, looking inside Plugin.so with nm Plugin.so | grep -i CommonInfo it gives an 'U' for this symbol (unresolved), which is perfectly ok.
Also, looking inside the binary of loader with nm loader.so | grep -i CommonInfo I could find the symbol with 'T', which is also ok.
Question is, shouldn't dlfcn.h unresolve the symbol in question from the main binary? Without this feature it becomes quite hard to use these stuff... Do I have to write a class factory function for CommonInfo, load it with dlfcn from the plugin and call that?
Thanks in advance,
Dennis
I haven't looked closely at your code, but I have in the past found behavior like you describe in the title when I did not link the executable with -E. (Or -Wl,-E when linking with gcc rather than ld.)
Note that not all platforms let the shared libraries take symbols from the calling binary. Linux and the *BSDs allow you to. But if you ever want to port to, say, Windows, you will not be able to use this pattern. I believe there are also some Unix-type OS's that won't let you do this. (It's been a while so I don't remember... Maybe it was Solaris?)