undefined reference when calling code in downloadable kernel module - c

Following on from a previous question Using system symbol table from VxWorks RTP.
I am porting an existing vxworks kernel module to an RTP, however, much of the actual functionality is still embedded in other "downloadable" kernel modules. These are loaded using loadModule (as part of the startup process), and so should be in the system symbol table at the point my RTP runs.]
However, I cannot get my RTP to build, getting errors from the linker regarding undefined references.
How can I persuade the linker to ignore references to these functions? I am passing the -Xbind-lazy -non-static options to the linker.
As an example, the kernel module (built as database.out) might contain code such as
void writeDatabaseValue(int , char*);
and my RTP application code calls it in the usual way
void main (int)
{
//do some stuff
writeDatabaseValue(0,"foo"); //Linker error here
taskDelay(100); //but no linker error here
}
I have tried adding database.out to the link line using -l:database.out, which resolves the reference to writeDatabaseValue, however I then get into dependency hell, as the linker then tries to resolve all of database.outs references, including all of the standard vxworks api calls.
EDIT: Just for extra complication, some of the kernel module code I want to call is in the same module that actually spawned my RTP......

You are really trying to shoehorn one environment into a totally different one and are experiencing the pain inherent in this approach. I don't believe you will be able to get the linker to ignore the references.
Might be better to use symbolic links (available from within the Workbench environment) to source files and use those in a RTP project.
Or create dynamic libraries based on the DKMs (again, use symbolic links) and link those against your RTP.
As an example, let's say you have the following Workbench workspace:
DKM1
DKM2
RTP
Based on the question, you are attempting to link DKM1 & 2's object files in the RTP and are experiencing pain.
A better approach is to add a project link to the source files in DKM1 & DKM2 and have them compiled in the RTP. Because it is a link (instead of a copy) then changing the file in the DKM (to fix a bug for example) would also change it in the RTP.
In the RTP project, do a "New > Directory". Select the "advanced" button and check the "link to existing directory" then select the "DKM1" directory.
All the source file in the DKM1 will now be part of the RTP. Do the same with DKM2.
When you compile the RTP project, these new files should also be compiled.

Related

Creating Backwards Compatible Drop In Statically Linked DLL

I have a C-based DLL that I wrote years ago for a project and it exports a set of functions that define an API. Now I need to re-write this DLL's internals but keep the API exactly the same.
The user of the DLL used static linking and they do not want to or are unable to recompile their executable.
I've noticed that the RVAs of the exported functions are different. My understanding is that means the executable won't be able to find the functions unless it is re-linked with the updated lib file.
Is there a way in VS2017 to force an exported function to use a specific RVA? I checked the Microsoft LINK DEF file format and I didn't see an option in there.
Even if it is possible, is fixing the RVAs enough to ensure the old executable will be able to use the updated DLL or are there additional complications that make this a non-starter?
Thanks.
When you statically link an EXE module against a DLL, you do indeed link against the the DLL's import library (a .LIB) created alongside the DLL when the DLL was built. This is not the same thing as linking against a static library which is confusing because those are also .LIB files.
The first thing you should do is figure out if your EXE module has an import entry for said DLL using a tool like Dependency Walker, Dumpbin, pelook or your favorite PE analyzer tool. If there is no DLL import entry, you have have probably linked the EXE against a static library as described by #HAL9000 's answer. Short of reverse-engineering the EXE, your best bet would be to rebuild the module as suggested if possible.
Otherwise, if you do find an import for said DLL, then yes you can swap out a newly-built DLL provided you have the same export (function) names and/or ordinal values as the original. DLLs find function by export names and/or ordinal values, not RVAs which in this case are only an internal detail. Whether the DLL is implicitly loaded (from being statically-linked) during process (EXE) initialization (before the EXE's entry point is called) or explicitly loaded (via code using LoadLibrary, etc.) the whole point of being a DLL is that it is a module is designed to be dynamically replaced and Windows was designed around this concept. The internal RVAs both within the EXE (referencing the DLL) and the DLL itself do not need to match an old DLL's values; this bookkeeping is automatically handled by the Windows loader during a process also known as runtime linking.
In the event the EXE is linked against said DLL and ALSO specifies hard-coded addresses (RVAs) for the DLL's exported functions (a process known as static binding), Windows will still verify the addresses still internally reflect the correct values in the DLL that is actually loaded which may be a different, updated DLL. This is done via a timestamp check in the import section for the DLL. If there is a mismatch, the Windows loader tosses-out all of the static RVAs and updates them with the current values incurring a slight performance penalty, but the program will still load. FWIW the bind.exe tool to do this static binding no longer ships with the Visual C++ toolset as the performance gain in modern versions of Windows is minimal. This optimization used to be be common practice to speed up load times, especially in OS-supplied system DLLs, but shouldn't affect what you are trying to do one way or the other.
If the user has statically linked in your library, then it is not a DLL, and making a drop in replacement without relinking is not possible. At least not without some ugly hacks. The old library functions have been copied into the executable, so there are no way around editing the executable. If you can't recompile or relink, then it is probably easier to rewrite the executable from scratch.
Mucking around with adresses of functions in your new DLL, if possible, can't have any effect if the executable doesn't have any code to load a DLL at all.

Getting known library paths from ldconfig for use with dlopen

I have a program written in C that uses dlopen for loading plug-in modules. When the library is dynamically loaded, it runs constructor code which register pointer to structure with function implementations with the main application by use of exported function. I want to use absolute path for specifying the file to dlopen.
Then I have other part of the program with takes file, determine if it is ELF, then looks into the ELF header for specific ELF section, read this section and extract from it pertinent information. This way it filters only shared libraries which I have previously tagged as a plug-in module.
However, I am solving a problem how to discover them on the fly (in portable Linux way, i.e. it will run on Debian and on Fedora too and so on) from the main program. I have been thinking about using ldconfig for this. (As the modules will be installed by way of distro packaging system, APT for example.) Is there any way how to programmatically get the string list of known libraries from C program other than directly reading the /etc/ld.co.cache file? I was thinking that maybe there is some header library which will give char** when I ask.
Or, maybe is there any better solution to my problem?
(I am proponent of using standard system components that programming one-off solutions which will need support in the future.)

How to dump an executable SBCL image that uses osicat

I have a simple common lisp server program, that uses the osicat library to interface with the posix filesystem. I need to do this because the system creates symbolic links to files, and uses the POSIX stat metadata, and neither of those things are straightforward to do in portable lisp.
I am managing the dependencies with quicklisp, and I have all of this pinned to a working distribution. The app is portable between CCL and SBCL, and I tend to build it in the first and deploy it using the latter. I declare the dependencies for the app with an asdf defsystem, and I can use quicklisp to load it for easy development from local projects.
For deployment I was just using some ansible playbooks that replicated a developer environment on a remote (.e. setting up quicklisp, pushing code into local projects, running out of a user home directory) which was hacky, but mostly ok. More recently, as it's becoming more stable I have been compiling it using sb-ext:save-lisp-and-die, using a simple compile script. This means I get an executable that I can run more like a server, with service management scripts, and an anonymous user account.
This has been working very well, and so I recently moved this step to the next level, and I'm building .deb packages with my compile script, so I can bundle up everything into a relocatable binary. This also sort of works, but the resultant binaries are not relocatable from the original build host. They refuse to start up, and it appears that they try to dynamically load a shared library for osicat
Unhandled SIMPLE-ERROR in thread #<SB-THREAD:THREAD "main thread" RUNNING
Mar 15 12:47:14 annie [479]: {10005C05B3}>:
Mar 15 12:47:14 annie [479]: Error opening shared object "libosicat.so":
Mar 15 12:47:14 annie [479]: libosicat.so: cannot open shared object file: No such file or directory.
it looks like the image expects to find this in the original build tree's quicklisp archives
(ERROR "Error opening ~:[runtime~;shared object ~:*~S~]:~% ~A." "/home/builder/buil...quicklisp/dists/quicklisp/software/osicat-20180228-git/posix/libosicat.so
(SB-SYS:DLOPEN-OR-LOSE #S(SB-ALIEN::SHARED-OBJECT :PATHNAME #P"
so poking around the source, I realise that when quicklisp fetches osicat and exercise its build operation, it compiles this DLL to wrap it's interface with the system libaries, rather than just ffi to them directly - possibly because it's using cffi groveller, I don't really know much about cffi (yet). This is fine, but rather than linking to a .so using the system linker it's trying to dlopen it from a fixed path, which is not very portable, and kind of breaks the usefulness of save-image
I'm a bit stumped at this point, but before I go diving any much further into QL and cffi builds, I wondered if there's some build or compile configuration I'm missing that would make it bootstrap in a more 'static' fashion or influence the production of the wrapped library. Ideally I just want a single blob I can wrap in an installer, and link it against system libraries, but if I have to deploy some additional artefacts that's probably alright. I don't know how to make the autogenerated shared objects occur at a more controlled path.
At that point though, I may as well write a .so for my posix calls and distribute this alongside the app and try and FFI to it more directly. That would be a bit of a pain, so I would prefer to not do this.
You're right, when a dumped image is starting up, it is trying to reload the shared libraries. Which, as you are experiencing, is not working if the image is not starting on the machine it was dumped on.
This is almost what static-program-op set out to solve. A simple system definition like this should help you compile a static program:
(defsystem "foo"
:defsystem-depends-on ("cffi-grovel")
:build-operation "static-program-op" ; "asdf" package is implied
:build-pathname "foo" ; path of the generated binary
:entry-point "foo:main" ; function to use as the entry point
;; ... everything else ...
)
If your system depends on grovel files (defined by :cffi-wrapper-file, :c-file or :o-file), such as the ones provided by osicat, then it will statically link those to your dumped image.
However, it's not perfect.
Essentially, there are still some issues. Some are being fixed upstream by CFFI itself (e.g. not reloading shared libraries of the statically embedded libraries), others are a bit harder. (E.g. SBCL default compilation options don't let you use static-program-op by default. This is being fixed in Debian builds of SBCL, but other distributions are being less responsive.)
This is obviously a problem that the community at large has met, and there are several libraries that are around to help:
The first one, that has been around for a while, is Deploy. The approach it takes is that it embeds the dumped image and the libraries into an archive, and rearranges things for the binary to load them from wherever it is extracted to.
The second one, which I am biased towards because I made it, is linux-packaging. It takes the approach of fixing static-program-op by extending it, but requires you to build a custom SBCL. However, it generates distribution packages like .deb and .rpm, in order to be able to specify dependencies for system shared libraries (e.g. if you depend on sqlite, it will figure out which package provides it and add it as a dependency in the .deb). I highly recommend looking at the .gitlab-ci.yml for examples.
I recommend reading the webpages of both of those libraries to make your choice, they both have their advantages and drawbacks. <joke>Obviously, linux-packaging is superior.</joke>
Maybe you can use sb-posix:symlink and sb-posix:fstat on SBCL instead, removing the osicat dependency by feature toggle.

How to install library from source code, without any config nor Makefile?

Sorry for what is likely a simple question -- still getting a handle on Linux.
I've been attempting to install the 'FreeMODBUS' library, however judging from the website, it is somewhat outdated. The download link leads to nowhere, however the source code is still accessible via Sourceforge as a .zip download. In the past I've only dealt with libraries that come via .tar, however the bigger issue is that there seems to be no config, makefile nor README detailing the installation process.
Additionally I tried including all of the source code and header files supplied within my Eclipse project. I was hoping that this would be the lazy man's solution to all of my problems -- or at the very least I could compile the .so file myself -- however I'm still getting 'undefined reference to [Function]' errors. From what I understand this is a linking issue. To the best of my knowledge all inclusions are correctly set up.
Is this library deprecated, or is there a step to the process that I'm overlooking? Thanks!
Some superfluous project information:
I'm using modbus for a C project. The network is ideally going to be setup so that a number of modbus enabled devices are configured on a single daisy chained RS-485 hub -- therein containing all our modbus communications to a single comm port in a rather complex system.
The problem however is that popular open source modbus library, 'libmodbus', doesn't appear to lend itself to this configuration. In order to instantiate a modbus node instance, it requires the comm port to be passed, as opposed to the unit's modbus id.

Prevent linking of mallocr.o file within libc.a

This is for my company, so I'm leery of being too specific, but I'll try.
I am attempting to add support for some existing ANSI C code to our platform. I am using GCC 4.7.2 as well as the GNU linker. We use part of newlib, but also some other C libraries, specifically libc.a. The end goal of this is to get an EXE or ELF image (this is for a PowerPC architecture micro) to put into the micro's RAM. This is being done on Windows XP. I am simply using a batch file, not a build environment or toolchain.
One of my build errors is a multiple definition problem of malloc/free functions. The cmd window spits out the error that there are definitions of these in both malloc.o and mallocr.o. Both of these are within libc.a. I've been told the "r" in mallocr.o is for reentrancy. I've also been told our platform does not support reentrancy.
I'm trying to resolve this error by preventing the linking of mallocr.o from within libc.a. This is the part where I am lost, I don't know how to do this. Google hasn't turned up anything helpful, and I haven't found a question on this site yet that answers my problem. I don't know if this is even possible.
There is really no specific code snippet to include in this question. Below is the error from the cmd window. I've *'d out company specific things I am not comfortable sharing.
c:\***\platform\2_2_0_r2013-2_x86-32\tools\gcc_4_7_2\ppc\bin\..\powerpc-eabi\lib\libc.a(mallocr.o): In function `free':
mallocr.c:(.text+0x19c): multiple definition of `free'
c:\***\platform\2_2_0_r2013-2_x86-32\tools\gcc_4_7_2\ppc\bin\..\powerpc-eabi\lib\libc.a(malloc.o):malloc.c:(.text+0x28): first defined here
c:\***\platform\2_2_0_r2013-2_x86-32\tools\gcc_4_7_2\ppc\bin\..\powerpc-eabi\lib\libc.a(mallocr.o): In function `malloc':
mallocr.c:(.text+0x468): multiple definition of `malloc'
c:\***\platform\2_2_0_r2013-2_x86-32\tools\gcc_4_7_2\ppc\bin\..\powerpc-eabi\lib\libc.a(malloc.o):malloc.c:(.text+0x0): first defined here

Resources