How to calculate target address in relocatable elf - linker

In the standard elf , the relocation entry is of the following type :
typedef struct {
Elf32_Addr r_offset;
Elf32_Word r_info;
Elf32_Word r_addend;
} Elf32_Rela;
Here I understand that the r_offset tells the memory location to apply the relocation . However , I have not been able to understand through any link I gone through so far regarding how to combine r_info and r_addend to get a final target address.
Can someone please help me understand this or provide a good layman level link that I can go through ?

Related

How can I make sure that my struct fits in a memory area defined in a linker script?

I'm having a problem very similar to this one, but no answer there is helping me. Building with gcc on ARM Cortex M4.
I have:
a memory area defined in a linker script
a complex structure, the size of which is computed and stored in a define in a header file
I would like:
a compile or link time error, if that structure does not fit in the memory area.
I tried (like the person asking the question I linked to above):
importing linker symbols with extern uint8_t __AreaStart[]; and extern uint8_t __AreaEnd[]; from the linker script. No compile time error, which makes sense since the values in the Area symbols are not known at compile time.
I could see:
making ASSERTS in the linker script, but that would mean giving the size of the struct to the linker, and I'm not sure how to do that. For one, the size is currently in a pre-processor macro, not in an actual C symbol (it would be neat not to spend actual memory for communicating size from C to the linker).
giving the struct type to the linker, so if I could get the equivalent of sizeof(type) in the linker script.
actually defining a variable of that type in the memory area, in the C file. If it doesn't fit, the linker should complain. The problem is that this area holds user data, and needs to stay untouched over reprogramming. It cannot be part of the final binary, or user data would get overwritten. I could make an additional separate application just for the sake of checking, but I feel there must be a simpler solution (as of today, the Area does not even have a Section. Maybe add a NOLOAD section there?).
How should I go about failing at building, knowing that the size of the struct is available in a macro, generated at each build?
Background: the struct is generated by protobuf, that's why the size is considered variable. Maybe I could make the check after generating the struct.
A solution is to create a section in the Area in the linker script:
SECTIONS
{
.config_no_load (NOLOAD) :
{
. = ALIGN(4);
*(.config_no_load*);
KEEP(*(.config_no_load))
} > CONFIG1
}
KEEP is required to avoid optimization of the unused memory. CONFIG1 is the Area:
MEMORY
{
/* ... */
/* Configuration areas (App data) */
CONFIG1 (rx) : ORIGIN = 0x000f6000, LENGTH = 0x0100
}
Then in the C code, define a variable that is too large:
__attribute__((section(".config_no_load"))) __attribute__((unused))
static uint8_t volatile fake_config_header[0x200] = {0};
results in error as such:
LD application.elf
/usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: application.elf section `.config_no_load' will not fit in region `CONFIG1'

C compiling: relocation truncated to fit R_X86_64_PC32 against symbol

/* my program
author/date: me/now
*/
# include <stdio.h>
# define XX 1000
# define YY 20000 /* value of 1000 is ok */
# define ZZ 6000
/* global variable declaration */
int some_variable_this;
int some_variable_that;
double data[XX][YY][ZZ];
static void some_procedure_this ( void )
{
}
static void some_procedure_that ( void )
{
}
int main ( int argc, char *argv[] )
{
}
writing a quick C program to reformat some data.
when compiling via gcc myprogram.c if I make the global data array too large I get the compiler error:
relocation truncated to fit R_X86_64_PC32 against symbol 'some_variable_this'
relocation truncated to fit R_X86_64_PC32 against symbol 'some_variable_that'
My goal is to do a quick c code to reformat some data.
What does this R_X86_64_PC32 mean?
Is there a compiler flag I can used to get around this?
Is there a better way to code this, in C, while still maintaining quickness of writing the code and simplicity for human readability?
this on gcc 4.3.4 in linux if it matters.
What does this R_X86_64_PC32 mean?
It is an ELF relocation type used in ELF for x86_64. This particular type expresses that the location of the referenced data is computed based on a 32-bit offset from the an address related to the program counter. I interpret the diagnostics to indicate that the needed offsets are too large to fit in the provided 32 bits, which means that the compiler generated code that, in practice, the linker wasn't able to link correctly.
Is there a compiler flag I can used to get around this?
Maybe. The basic problem is that you've defined an object that is larger than the authors of your compiler imagined (at the time) that anyone would be able to accommodate. You're going beyond its design limits.
There may be options that would mitigate this effect. In particular, you could try twiddling the -fPIC and / or -fPIE options, and there may be others.
Is there a better way to code this, in C, while still maintaining quickness of writing the code and simplicity for human readability?
It's not a C problem per se, it's an implementation problem. Yet GCC is not wrong or faulty here as far as the language standard is concerned -- the standard does not obligate implementations to accept every possible program that is technically valid.
With that said, you could also try moving the declarations of some_variable_this and some_variable_that after the declaration of data. Conceivably, it might also help to declare those variables static, or to move them (or data) to a separate shared library.

How can my C code find the symbol corresponding to an address at run-time (in Linux)?

Given a function or variable run-time address, my code needs to find out the name and, if it's a variable, type information of the symbol. Or at least provide enough information for later, off-line extraction of the name (and type info).
It is Linux code and it is assumed debug information is available.
I tried to look into the ELF file format, binutils and all but the subject is huge, so I was hoping somebody can help me narrow the scope.
I can see the following types of solutions:
find the range of the code/data segments of the modules currently loaded in memory - HOW TO DO THAT ?. Save the address's module and segment name and offset in it's segment. Off-line then use binutils to find the symbol in the module's debug info - again, HOW TO DO THAT?
use some API/system services I do not know of to find the symbol and info at run-time - HOW?
Thank you in advance.
GNU libc provides a dladdr function for this exact purpose. However, it only works on functions, not variables.
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <dlfcn.h>
int dladdr(void *addr, Dl_info *info);
The function dladdr() takes a function pointer and tries to resolve
name and file where it is located. Information is stored in the
Dl_info structure:
typedef struct {
const char *dli_fname; /* Pathname of shared object that
contains address */
void *dli_fbase; /* Address at which shared object
is loaded */
const char *dli_sname; /* Name of symbol whose definition
overlaps addr */
void *dli_saddr; /* Exact address of symbol named
in dli_sname */
} Dl_info;
If no symbol matching addr could be found, then dli_sname and dli_saddr
are set to NULL.
dladdr() returns 0 on error, and nonzero on success.
Of course, usually I do this sort of thing from gdb, not within the program itself.
What you want to look at is the Binary File Descriptor library specifically the symbol handling functions. libbfd provides a common set of functions for manipulating and reading various object formats. It does this by providing an abstract view of object files and then has specific back ends to handle the details of specific object types and architectures. ELF file formats are supported as is most likely the architecture you want to use.
I don't find libbfd difficult to use but I am always open to alternatives and libelf is another one. You will probably want to look at the gelf_getsym function specifically.
C is a fully-compiled language. The names and types and other info about variables are generally discarded in the compilation process.
An exception is that most compilers will produce an executable with debugging information included, so that a live debugger has access to this information. This info is totally OS-specific, and even compiler-specific, and might even be in parts of memory not accessible to the program.

Finding address of a C struct inside an ELF file compatible to ARM Architecture

In my project I defined: (This is not the real code - for abstraction purpose)
typedef struct {
...
} my_struct;
In some C file I declared:
my_struct my_struct_inst;
And in other 2 C files I used that struct by declaring:
extern my_struct my_struct_inst;
and used it's contents.
I compiled that code to ARM with RVCT2.2 and trying to find the address of that structure:
1) When does memory being allocated to my_struct_inst? On compilation time? On run time?
2) In the disassembly I can see that in the .FLASH_RAM section (probably where this kind of data belongs) there is some reference like:
my_struct_inst % 0x190
I got it with IDA. What does it mean? (That that struct instance will start at offset 0x190 from the beginning of .FLASH_RAM section?)
3) How exactly the actual address (where the struct actually sitting in memory) is being accessed when I write my_struct_inst.some_member (should I read some ABI documentation?)
The memory for your structure will be allocated at compilation time.
The address will be defined by your linker script. To see the address of the structure (assuming it is a global variable), you will need the generated ELF file (lets call it a.elf, for this example). Then just run:
arm-eabi-objdump -t a.elf | grep my_struct_inst
Objdump "-t" will list all global symbols with its address and the section it belongs too. You can replace the "objdump" by any cross-compiled objdump that you have.

Cell SPU error in C

When I compile a SPU program, I get the following compilation error:
(.text+0x28): relocation truncated to fit: SPU_ADDR18 against symbol `_end' defined in *ABS* section in spu
What does it mean?
The error comes only after I have included at the very beginning:
#define CACHE_NAME MY_CACHE
#define CACHED_TYPE double
#define CACHELINE_LOG2SIZE 11
#define CACHE_LOG2NWAY 2
#define CACHE_LOG2NSETS 4
#include <cache-api.h>
The error means:
an object references the symbol '_end' using the relocation mode SPU_ADDR18
the actual adress of the symbol '_end' is too big for the mode of reference used.
_end is a symbol traditionally defined at the end of code and data segment. So most probably, you have more code and static data than the SPU support. (SPU support 256Kb that is 18 bits of address, so I guess that the relocation kind SPU_ADDR18 is the most flexible one).
The error means that the elf executable that you're building doesn't fit into SPU memory; probably because the cache-api.h header defines some static/global variables. Notice that your executable can't use more than 251Kb of memory (part of which will likely be part of the job kernel, code and data).

Resources