Currently, I'm learning RISC-V, use the RISC-V toolchain, and edit a new ld script for my embedded. I write a example, and compile to watch the opcode.
Example:
#include <stdio.h> //float.c
int main()
{
float a=1.04;
printf("a=%f\n",a);
return 0;
}
My steps is:
1. riscv64-unknown-elf-gcc -S float.c *//generate assembly code*
2. riscv64-unknown-elf-as float.s -o float.o *//generate obj file*
3. riscv64-unknown-elf-ld -T elf64lriscv1.x float.o *//use own script to link, -T is using other script*
and then,it will show "float.c:(.text+0x50): undefined reference to `printf'
I'm try
Add -lc parameter, but doesn't working, it will show more undefined message.
My ld script
OUTPUT_FORMAT("elf64-littleriscv", "elf64-littleriscv","elf64-littleriscv")
OUTPUT_ARCH(riscv)
ENTRY(_start)
SEARCH_DIR("/path/to/install/riscv/toolchain/riscv64-unknow-elf/lib");
/*MEMORY{ //for my embedded allocation
flash : org = 0x0, l = 0x10000
ram : org= 0x10000, l = 512
}*/
SECTIONS{
_start =0x10000;
.text :
{
*(.text)
}
.bss :
{
*(.bss)
*(.sbss)
}}
Also, i'm trying to use the default script, like this command:
$ riscv-unknown-elf-ld float.o -o float
but it is same result....
please help me!
Regards!
printf is provided by the C standard library (and is very difficult to implement). You need to link it (perhaps by adding -lc to your riscv-unknown-elf-ld command, or by giving the complete path of that library)
You might pass additional options to your riscv-unknown-elf-ld perhaps -M, -L search-dir, --trace, --verbose, etc. Read also more carefully the chapter about ld scripts.
Since you are cross-compiling, you might need to cross-compile some libc from source code.
You need to spend more time understanding the behavior of linkers and ELF object files and executable format (see also elf(5)). Consider reading Linkers and Loaders
You could use other cross- binutils programs (like cross- objdump, nm, readelf etc...) to explore the relevant object files.
If you are coding for a bare metal system, you might want to compile in freestanding mode (passing -ffreestanding to your GCC) and provide so implement your own printf (or other output) function. Existing free software C libraries could inspire you (but you need to find one or work many months to develop some equivalent). Study for inspiration the source code of GNU libc or of musl-libc.
I recommend also reading about OSes, e.g. Operating Systems: Three Easy Pieces (since the OS concepts are relevant to you, because an embedded system on the bare metal share features with OSes). OSDEV wiki might also be helpful (but is not about RISC-V).
You could need several months of work (or even years), so budget it appropriately.
BTW, I am surprized that you use a float in your example. Floating point is difficult. See floating-point-gui.de ; For a first try, I would consider using integer only.
Related
This post is asking about modifying / patching or even hexediting - due to lack of better methods (see Notes) an elf binary to adjust functions / symbols / versions they point to - and keeping ld.so happy + asking for some Tools to ease this process.
Recompilation of the binaries is not in the scope of the solution I am looking for, neither is a dissassembly of the binary, neither is using LD_* env. variables (not because they aren't valid solutions, but due to my different use-case) except for solutions akin to the one here: writing a 'dummy' function, which exposes the desired soname, and does tricks ld.so in some clever way.
There are 2 situations, for which I'd appreciate some help from the community:
The first one, binary_a, has following unmet dependency, amongst others:
$ ldd binary_a
binary_a: /usr/lib/x86_64-linux-gnu/libcdio.so.13: version `CDIO_13' not found (required by binary_a)
which is normal, since my OS has a newer version of libcdio, namely libcdio.so.17.
My goal is to try to adjust the binary to use that one instead.
What I did was :
use an hexeditor (since I couldn't find a Tool to do that) to change CDIO_13 -> CDIO_17 in the .dynstr section (yes, this version appears in the libcdio.so.17 file - checked that using objdump -SdV libcdio.so.17 or objdump -T libcdio.so.17 )
use patchelf (or again hexedit) as such:
$ patchelf --replace-needed libcdio.so.13 libcdio.so.17 binary_a
but this doesn't seems to work, since ldd still complains (although it is actually ld.so which complains, since ldd is just a bash wrapper script around it):
$ LD_DEBUG=libs ldd ./binary_a | fgrep -i libcdio.
30345: find library=libcdio.so.17 [0]; searching
30345: trying file=/usr/lib/x86_64-linux-gnu/libcdio.so.17
30345: /usr/lib/x86_64-linux-gnu/libcdio.so.17: error: **version lookup error: version `CDIO_17' not found (required by ./binary_a) (continued)**
**./binary_a: /usr/lib/x86_64-linux-gnu/libcdio.so.17: version `CDIO_17' not found (required by ./binary_a)**
libcdio.so.17 => /usr/lib/x86_64-linux-gnu/libcdio.so.17 (0x00007fbadca1e000)
To confirm: at this point, there are not references to the old .so , or to the old version (CDIO_13) in the binary, also sonames for the dependency (see soname explained ) is also valid & objdump / readelf have no issues with modified binary: they see the new version, i.e. CDIO_17 throughout the binary.
My guess is that the problem for which ld rejects the binary might be related to the vna_hash entry in the Elfxx_Vernaux struct. (see 3 for reference) being messed up by the edit, or some other anti-tampering safeguards which elf format has, makes ld to invalidate it, or is ld.so's cache somehow interferring ?
Or is it that I'm hitting the case "if two .so file has same function name, only the first one would accepted." mentioned 2 s.o. same name ?
The removal of libcdio (+ some other cd/dvd-related libs), should, theoretically, not impact the functionality of binary_a (media player), since the laptop doesn't have a dvd drive anyway.
There is also the possibility of 'weakening' those symbols, however, am not sure if that would suffice to have ld.so ignore them - haven't tested, however according to 5 it should take me closer to reaching my goal.
The second case involves, binary_b, which has a dependency to libncurses.so.6, on version NCURSES6_5.0.19991023.
My goal here is to force it to use libncurses.so.5 which only exposes version NCURSES_5.0.19991023 -notice the lack of '6' after 'NCURSES' which, by hexediting it, would change the length of the corresponding entry in the .dynstr Table.
As with previous binary, this version exists in the libncurses.so.5 file, and the file is found & readable by ldd.
Notes:
(1) I've tried elfsh (which after fixing some compile error, errors out about not recognising the elf header), rizin/cutter...
I've tried patchelf (before doing any modification), which fails for following command, presumably because the file is stripped already:
- $ patchelf --remove-needed libcdio.so.13 binary_a
- $ ldd binary_a
Inconsistency detected by ld.so: dl-version.c: 205: _dl_check_map_versions: Assertion `needed != NULL' failed!
(2) Objcopy and elfedit seem like good candidates; however, the info gathered from their man pages about (if) such possibility & how to do it is lacking + my understanding about this whole s.o. libs subject - remains meager, so I'd appreaciate some good pointers here !
(3) The other idea was to try to manually add a new dummy version entry in the .dynstr Table, which is not trivial (see dt_hash article), but I'd need a more step-by-step walkthrough of what the steps should be. Thus, I would add NCURSES_5.0.19991023, and take its offset and overwrite the vna_name entry in the corresponding Elfxx_Vernaux structure with this offset and / or overwriting the vna_flags entry (?), not sure ... 3
There is a similar case in 5, in which the author deals with a similar case (although a more simplistic one, one in which the versions already exists in the binary), and another one in Trick ldand those solutions I could maybe use, provided I'd first managed to somehow add my needed version in the elf header...
Any pointers as to what is wrong (about ldd complains) and how to achieve my goals, would be very much appreciated, Thanks !
References:
NewAppsOnOldGlibc
Symbol Versioning in the ELF header
I have downloaded libgcrypt library source code and I want to customize this standard shared library by adding my function inside one particular
source code file .
Although compilation/build process of customized shared library is successful, but it shows error at linking time.
Here is what I have done .
inside /src/visibility.c file, I have added my custom function,
void MyFunction(void)
{
printf("This is added just for testing purpose");
}
I have also include function prototype inside /src/gcrypt.h
void MyFunction(void);
#build process
./configure --prefix=/usr
sudo make install
nm command find this custom function.
nm /usr/lib/libgcrypt.so | grep MyFunction
000000000000dd70 t MyFunction
Here is my sample code to access my custom function.
//aes_gcrypt_example.c
#include <stdio.h>
#include <gcrypt.h>
#include <assert.h>
int main()
{
MyFunction();
return 0;
}
gcc aes_gcrypt_example.c -o aes -lgcrypt
/tmp/ccA0qgAB.o: In function `main':
aes_gcrypt_example.c:(.text+0x3a2): undefined reference to `MyFunction'
collect2: error: ld returned 1 exit status
I also tried by making MyFunction as extern inside gcrypt.h, but in that case also I am getting same error.
Why is this happening ?
Is the customization of standard library is not allowed ?
If YES, then is there any FLAG to disable to allow customization ?
If NO, what mistake I am making ?
It would be great help if someone provide some useful link/solution for the above mentioned problem. I am using Ubuntu16.04 , gcc 4.9.
Lower-case t for the symbol type?
nm /usr/lib/libgcrypt.so | grep MyFunction
000000000000dd70 t MyFunction
Are you sure that's a visible function? On my Ubuntu 16.04 VM, the linkable functions defined in an object file have T (not t) as the symbol type. Is there a stray static kicking around and causing confusion? Check a couple of other functions defined in libgcrypt.so (and documented in gcrypt.h) and see whether they have a t or a T. They will have a T and not t. You'll need to work out why your function gets a t — it is not clear from the code you show.
The (Ubuntu) man page for nm includes:
The symbol type. At least the following types are used; others
are, as well, depending on the object file format. If lowercase,
the symbol is usually local; if uppercase, the symbol is global
(external).
The line you show says that MyFunction is not visible outside its source file, and the linker agrees because it is not finding it.
Your problem now is to check that the object file containing MyFunction has a symbol type T — if it doesn't the problem is in the source code.
Assuming that the object file shows symbol type T but the shared object shows symbol type t, you have to find what happens during the shared object creation phase to make the symbol invisible outside the shared object. This is probably because of a 'linker script' that controls which symbols are visible outside the library (or maybe just compilation options). You can search on Google with 'linker script' and various extra words ('tutorial', 'provide', 'example', etc) and come up with links to the relevant documentation.
You may need to research documentation for LibTool, or for the linker BinUtils. LibTool provides ways of manipulating shared libraries. In a compilation command line that you show in a comment, there is the option -fvisibility=hidden. I found (mostly by serendipitous accident) a GCC Wiki on visibility. See also visibility attribute and code generation options.
What is the purpose of the features.h header? Why and when can it be used in my code?
Does it define source features supported by the system?
Or does it define some additional things which must be defined depending on other defines?
The features.h header file provides various macro definitions that indicate standard conformance to other header files, i.e. which features (hence the name) should be turned on or off depending on which standard the user wishes to use.
Most C/C++ compilers have command line options to handle standards conformance. Let's take GCC as an example: when you pass the -std=gnu9x option, you ask for the GNU dialect of the C99 standard. The features.h header makes sure that all other headers that include it will turn exactly those features on or off that are needed to support this particular dialect. This is achieved by #define -ing or #undef - ing some "intermediate" macros.
As a bonus, features.h also provides the glibc version information macros as well, and various other bits & bobs.
I have grepped POSIX 7 as explained at: https://unix.stackexchange.com/questions/340285/install-the-latest-posix-man-pages/483198#483198 and there are no hits for features.h, so it must be a glibc extension only.
In glibc 2.28, it is present at include/features.h.
One of the interesting things that it defines are version macros:
#include <stdio.h>
#include <features.h>
int main(void) {
printf("__GLIBC__ %u\n", __GLIBC__);
printf("__GLIBC_MINOR__ %u\n", __GLIBC_MINOR__);
return 0;
}
Ubuntu 16.04, which has glibc 2.23, this outputs:
__GLIBC__ 2
__GLIBC_MINOR__ 23
See also: Check glibc version for a particular gcc compiler
Also, this header seems to get included in most / all glibc headers, which might allow you to check if glibc is being used: How to tell if glibc is used but TODO I couldn't find a documentation for that.
From features.h File Reference
Defines on whether to include algorithm variants.
Less variants reduce executable size and compile time. This file is a GNU parallel extension to the Standard C++ Library.
So this file will include some algorithm listed in the reference page.
In general if you need to use any of the variables or functions defined in a header file, you need to include it in your program. This rule is valid for features.h also. You can see a URL for features.h for your reference below:
http://repo-genesis3.cbi.utsa.edu/crossref/heccer/usr/include/features.h.html
On Linux, is there a way to embed version information into an ELF binary? I would like to embed this info at compile time so it can then be extract it using a script later. A hackish way would be to plant something that can be extracted using the strings command. Is there a more conventional method, similar to how Visual Studio plant version info for Windows DLLs (note version tab in DLL properties)?
One way to do it if using cvs or subversion is to have a special id string formatted specially in your source file. Then add a pre-commit hook to cvs or svn that updates that special variable with the new version of the file when a change is committed. Then, when the binary is built, you can use ident to extract that indformation. For example:
Add something like this to your cpp file:
static char fileid[] = "$Id: fname.cc,v 1.124 2010/07/21 06:38:45 author Exp $";
And running ident (which you can find by installing rcs) on the program should show the info about the files that have an id string in them.
ident program
program:
$Id: fname.cc,v 1.124 2010/07/21 06:38:45 author Exp $
Note As people have mentioned in the comments this technique is archaic. Having the source control system automatically change your source code is ugly and the fact that source control has improved since the days when cvs was the only option means that you can find a better way to achieve the same goals.
To extend the #sashang answer, while avoiding the "$Id:$" issues mentioned by #cdunn2001, ...
You can add a file "version_info.h" to your project that has only:
#define VERSION_MAJOR "1"
#define VERSION_MINOR "0"
#define VERSION_PATCH "0"
#define VERSION_BUILD "0"
And in your main.c file have the line:
static char version[] = VERSION_MAJOR "." VERSION_MINOR "." VERSION_PATCH "." VERSION_BUILD;
static char timestamp[] = __DATE__ " " __TIME__;
(or however you want to use these values in your program)
Then set up a pre-build step which reads the version_info.h file, bumps the numbers appropriately, and writes it back out again. A daily build would just bump the VERSION_BUILD number, while a more serious release would bump other numbers.
If your makefile lists this on your object's prerequisite list, then the build will recompile what it needs to.
The Intel Fortran and C++ compilers can certainly do this, use the -sox option. So, yes there is a way. I don't know of any widespread convention for embedding such information in a binary and I generally use Emacs in hexl-mode for reading the embedded information, which is quite hackish.
'-sox' also embeds the compiler options used to build an executable, which is very useful.
If you declare a variable called program_version or similar you can find out at which address the variable is stored at and then proceed to extract its value. E.g.
objdump -t --demangle /tmp/libtest.so | grep program_version
0000000000600a24 g O .data 0000000000000004 program_version
tells me that program_version resides at address 0000000000600a24 and is of size 4. Then just read the value at that address in the file.
Or you could just write a simple program that links the library in questions and prints the version, defined either as an exported variable or a function.
Short:
I'm looking for something that will list all unresolved dependencies in an SO, taking into account the SOs that are in it's dependencies.
Long:
I'm converting a lot of static-compiled code to Shared Objects in Linux- is there an easy way to determine what other SOs my recently compiled SO is dependent on besides trial & error while trying to load it?
I'm sure there is a better way, but I haven't been able to find it yet.
I've found "ldd", but that only lists what the SO says it's dependent on.
I've also used "nm" to figure out once an SO fails to load to verify what other SO contains it.
I don't have code for you, but I can give pointers:
It's just a graph problem. You should use objdump -T to dump the dynamic symbol table for a given binary or shared object. You'll see many lines of output, and the flags can be a little confusing, but the important part if that symbols will either be *UND* or they'll have a segment name (.text etc).
Any time you see *UND*, that means that it's an undefined symbol which has to be resolved. Defined symbols are the targets of resolution.
With that, and a little Python, you should be able to find what you need.
"ldd -r foo.so" should print the set of symbols which foo.so needs but which aren't provided by its direct dependencies.
Alternatively, link foo.so like this:
gcc -shared -o foo.so foo.o bar.o -ldep1 -ldep2 -Wl,--no-undefined
This should fail (to link) if foo.o or bar.o uses something not provided by libdep1 or libdep2 or libc.