I'm Beginner of Linux System and I'm studying ELF File Format reading this Documents(http://www.skyfree.org/linux/references/ELF_Format.pdf).
But When i see related Document about Relocation, There is Strange Things in Relocation Calculation.
i know according to relocation type, it applies different way to calculate.
But look at this.
When R-type is R_386_RELATIVE, this document says the way to calculate "B + A".
However What is "A" meaning exactly? and How can I get this "A" Value in ELF File?
Please give me ur merciful answer.......;
From document you mentioned:
R_386_RELATIVE
The link editor creates this relocation type for dynamic linking. Its offset member gives a location within a shared object that contains a value representing a relative address. The dynamic linker computes the corresponding virtual address by adding the virtual address at which the shared object was loaded to the relative address. Relocation entries for this type must specify 0 for the symbol table index.
A
This means the addend used to compute the value of the relocatable field.
B
This means the base address at which a shared object has been loaded into memory during execution. Generally, a shared object file is built with a 0 base virtual address, but the execution address will be different.
Addend
As shown above, only Elf32_Rela entries contain an explicit addend. Entries of type `Elf32_Rel store an implicit addend in the location to be modified. Depending on the processor architecture, one form or the other might be necessary or more convenient. Consequently, an implementation for a particular machine may use one form exclusively or either form depending on context.
Base Address
To compute the base address, one determines the memory address associated with the lowest p_vaddr value for a PT_LOAD segment. One then obtains the base address by truncating the memory address to the nearest multiple of the maximum page size. Depending on the kind of file being loaded into memory, the memory address might or might not match the p_vaddr values.
So it boils down to next:
A is addend and calculated from Elf32_Rel or Elf32_Rela structure
B is base address and calculated from p_vaddr. Particular calculation depends on architecture.
You can observe relocation section of some binary/library file using readelf -r.
Related
I understand that PIC code makes ASLR randomization more efficient and easier since the code can be placed anywhere in memory with no change in code. But if i understand right according to Wikipedia relocation dynamic linker can make "fixups" at runtime so a symbol can be located although code being not position-independent. But according to many answers i saw here non-pic code can't ASLR sections except the stack(so cant randomize program entry point). If that is correct then what are runtime fixups are used for and why can't we just fixup all locations in code at runtime before program start to make program entry point randomized.
TL:DR: Not all uses of absolute address will have relocation info in a non-PIE executable (ELF type EXEC, not DYN). Therefore the kernel's program-loader can't find them all to apply fixups.
Thus there's no way to retroactively enable ASLR for executables built as non-PIE. There's no way for a traditional executable to flag itself as having relocation metadata for every use of an absolute address, and no point in adding such a feature either since if you want text ASLR you'd just build a PIE.
Because ELF-type EXEC Linux executables are guaranteed to be loaded / mapped at the fixed base address chosen by the linker at link time, it would be a waste of space in the executable to make symbol-table entries for internal symbols. So toolchains didn't do that, and there's no reason to start. That's simply how traditional ELF executables were designed; Linux switched from a.out to ELF back in the mid 90s before stack ASLR was a thing, so it wasn't on people's radar.
e.g. the absolute address of static char buf[100] is probably embedded somewhere in the machine code that uses it (if we're talking about 32-bit code, or 64-bit code that puts the address in a register), but there's no way to know where or how many times.
Also, for x86-64 specifically, the default code model for non-PIE executables guarantees that static addresses (text / data / bss) will all be in the low 2GiB of virtual address space, so 32-bit absolute signed or unsigned addresses can work, and rel32 displacements can reach anything from anything. That's why non-PIE compiler output uses mov $symbol, %edi (5 bytes) to put an address in a register, instead of lea symbol(%rip), %rdi (7 bytes). https://godbolt.org/z/89PeK1
So even if you did know where every absolute address was, you could only ASLR it in the low 2GiB, limiting the number of bits of entropy you could introduce. (I think Windows has a mode for this: LargeAddressAware = no. But Linux doesn't. 32-bit absolute addresses no longer allowed in x86-64 Linux? Again, PIE is a better way to allow text ASLR, so people (distros) should just compile for that if they want its benefits.)
Unlike Windows, Linux doesn't spend huge effort on things that can be handled better and more efficiently by recompiling binaries from source.
That being said, GNU/Linux does support fixup relocations for 64-bit absolute addresses even in PIC / PIE ELF shared objects. That's why beginner code like NASM mov rdi, BUFFER can work even in a shared library: use objdump -drwC -Mintel to see the relocation info on that use of the symbol in a mov reg, imm64 instruction. An lea rdi, [rel BUFFER] wouldn't need any relocation entry if BUFFER wasn't a global symbol. (Equivalent of C static.)
You might be wondering why metadata is essential:
There's no reliable way to search text/data for possible absolute addresses; false positives would be possible. e.g. /usr/bin/ld probably contains 0x401000 as the default start address for an x86-64 executable. You don't want ASLR of ld's code+data to also change its defaults. Or that integer value could have come up in any number of ways in many programs, e.g. as a bitmap. And of course x86-64 machine code is variable length so there's no reliable way to even distinguish opcodes from immediate operands in the most general case.
And also potentially false negatives. Not super likely that an x86 program would construct an absolute address in a register with multiple instructions, but it's certainly possible. However in non-x86 code, that would be common.
RISC machines with fixed-length instructions can't put a 32-bit address into a 32-bit instruction; there'd be no room left for anything else. So to load from static storage, the absolute addresses would have to be split across multiple instructions, like MIPS lui $t0, %hi(0x612300) / lw $t1, %lo(0x612300)($t0) to load from a static variable at absolute address 0x612300. (There would normally be a symbol name in the asm source, but it wouldn't appear in the final linked binary unless it was .globl, so I used numbers as a reminder.) Instructions like that don't have to come in pairs; the same high-half of the address could be reused by other accesses into the same array or struct in later instructions.
Let's first have a look at Windows before having a look at Linux:
Windows' .EXE files (programs) typically have a so-called "base relocation table" and they have an "image base".
The "image base" is the "desired" start address of the program; if Windows loads the program to that address, no relocation needs to be done.
The "base relocation table" contains a list of all values in a program which represent addresses. If the program is loaded to a different address than the "image base", Windows must add the difference to all values listed in that table.
If the .EXE file does not contain a "base relocation table" (as far as I know some 32-bit GCC versions generate such files), it is not possible to load the file to another address.
This is because the following C code statements will result in exactly the same machine code (binary code) if the variable someVariable is located at the address 12340000, and it is not possible to distinguish between them:
long myVariable = 12340000;
And:
int * myVariable = &someVariable;
In the first case, the value 12340000 must not be changed in any situation; in the second case, the address (which is 12340000) must be changed to the real address if the program is loaded to another address.
If the "base relocation table" is missing, there is no information if the value 12340000 is an integer value (which must not be changed) or an address (which must be changed).
So the program must be loaded to some fixed address.
I'm not sure about the latest 32-bit Linux releases, but at least in older 32-bit Linux versions there was nothing like a "base relocation table" and programs did not use PIC. This means that these programs had to be loaded to their "favorite" address.
I don't know about 64-bit Linux programs, but if a program is compiled the same way as the (older) 32-bit programs, they also must be loaded to a certain address and ASLR is not possible.
I am reading about copy_from_user(…) and copy_to_user(…) which copies from user and writes back to user space from kernel. when i see the internal implementation of copy_from_user(…), it is having two functions
access_ok(…) and memcpy(…), when i read about access_ok(…), it is saying access_ok(…) is used to check whether the userspace pointer is valid or not.
What check does access_ok(…) is doing to check the pointer validity?
In short it checks that memory is actually mapped at the given address. This is done by looking at the page mapping table, testing if that address has a matching entry there.
Furthermore it is tested that the address resides in user space, which is simply testing that its numeric value is in the lower half of the valid range of address values.
I have legacy Fortran code ranging in date from the 60s to 90s that I need to be able to compile.
The code works as it is written, even if it uses some old practices that are no longer standard.
It was successfully built on the Intel Visual Fortran 2011 Compiler and Visual Studio 2008. I am now on Visual Studio 2012 and Intel Visual Fortran 2013. I can't seem to find the right options to flip to allow it to build.
The major problem is that huge equivalence arrays are used and often instead of passing an array or an actual pointer to a subroutine they are just passing a single value of the pointer equivalence arrays and somehow it is implied to use a sequence of values. The main errors are
the type of actual argument differs from the type of dummy argument
if the actual argument is scalar, the dummy argument shall be scalar unless the actual argument is of type character or is an element of an array that is not assumed shape, pointer, or polymorphic
Once again. I know that the code does work as built. Any helpful suggestions will be appreciated.
The answer for my particular problem was to go to project properties -> diagnostics -> Language Usage Warnings -> Check Routine Interfaces and set it to "No".
It is about 1 year since your query, but I just had a similar problem that involved fortran pointers and dynamic memory allocations that I was able to fix.
A key problem was that memory address location values in the legacy code were equivalent to INTEGER*4 datatype whereas in the new operating system they were INTEGER*8. The way dynamic memory allocation worked was that the location of a dummy array 'HEAP(ii)' was used as an anchor point, relative to which the absolute address given by "malloc" could be referenced. If HEAP base address (i.e. LOC(HEAP(1)) was 11111, and if the absolute address freed by "malloc" was at memory address 1731111111111111, and if HEAP had been assigned to be integer*4 (or equivalently real*4), then the first location freed by "malloc" was equivalent to HEAP( (1731111111111111-11111)/4 + 1). Using HEAP(iaddress) as an argument in subroutine calls with iaddress at these insanely large index values allowed the appropriate portions of HEAP to be used as the array argument in the called subroutine.
Places with problems included:
POINT1.) The value of the absolute address of freed memory, as given by "malloc", had been stored at a position in HEAP() just after the stored calculation-data values. This address value was stored there so that it could be used later to free memory. If this INTEGER*8 address was stored across the boundaries of INTEGER*8 address registers for the new operating system/compiler, it would give a "HEXADECIMALS of DOOM" style crash, when you tried to access this stored INTEGER*8 memory address value based on the index of INTEGER*4 HEAP. This could be avoided by including an extra padding of 1 INTEGER*4 location before the storage spot for this stored value of the memory address. This was needed whenever the number of stored data values in the preceding data segment was an odd number of XXXX*4 data values. The stored memory address value could be read as an INTEGER*8 address, when it was needed, by EQUIVALENCE-ing INTEGER*4 HEAP() to INTEGER*8 LONGHEAP() and using an index value in longheap() that was about 1/2 of the insanely long index value used as the array index in HEAP() (with -1's and +1's to account for fortran indexing of arrays that starts from 1)
POINT2.) All variables that stored memory address locations needed to be tracked down and switched from INTEGER*4 to INTEGER*8. This was tricky in subroutines that called functions that called functions ... One construct to look for is the swapping of memory locations, TEMP = Iaddress; Iaddress = Jaddress; Jaddress = TEMP: in such swaps, make sure TEMP is INTEGER*8. Other memory-address arithmetic and temporary storage variables can cause problems as well. Also once you have made this switch, you need check whether these new INTEGER*8 variables have been used as arguments in calls to subroutines and functions. If so, you need to modify the called functions/subroutines appropriately and make sure that datatypes are consistent in all of the other calls to the same function/subroutine.
It might have been possible just to switch everything to *8 and check for statements involving the indexing arithmetic, but I wasn't sure if the new arrays of logical*8 values and some of the fancy stuff with the old integer*2 arrays would have worked.
I am trying to understand the internal working behind GDB commands. After initial homework of understanding about elf / shared libraries / address space randomization, I attempted to understand how GDB make sense between the executable and corefile.
solib.c contains the implementation of shared library processing. Esp am interested in the info sharedlibrary command.
The comment on the solib.c goes like this..
/* Relocate the section binding addresses as recorded in the shared
object's file by the base address to which the object was actually
mapped. */
ops->relocate_section_addresses (so, p);
I could not understand much from this comment. Can somebody explain me in plain english how relocation happens? i.e Every time when an executable loads a shared object, it is going to load at some location say X, and all the symbols inside the shared library will be located at fixed offset, say X+Y with some size Z. My question is, how does gdb does the same range of address relocation, so that it matches with the load segments in the corefile. How it takes that hint from executable.
how does gdb does the same range of address relocation, so that it matches with the load segments in the corefile
In other words, how does GDB find the relocation X?
The answer depends on the operating system.
On Linux, GDB finds _DYNAMIC[] array of struct Elf{32,64}_Dyns in the core file, which contains an element with .d_tag == DT_DEBUG.
The .d_ptr in that element points to struct r_debug (see /usr/include/link.h), which points to a linked list of struct link_maps, which describe all loaded shared libraries and their relocations in l_addr.
The relevant file in GDB is solib-svr4.c.
EDIT:
I see that, there are no .dynamic sections in the corefile.
There shouldn't be. There is a .dynamic section in the executable and a matching LOAD segment in the core (the segment will "cover" the .dynamic section, and have the contents that was there at runtime).
I read some documents that share library comiled with -fPIC argument,
the .text seqment of the .so will be shared at process fork's dynamic linking stage
(eq. the process will map the .so to the same physical address)
i am interested in who (the kernel or ld.so ) and how to accomplish this?
maybe i should trace the code, but i dont know where to start it.
Nevertheless, i try to verify the statement.
I decide to check the function address like printf which is in the libc.so that all c program will link.
I get the printf virtual address of the process and need to get the physical address. Tried to write a kernel module and pass the address value to kernel, then call virt_to_phys. But it did not work cause the virt_to_phys only works for kmalloc address.
So, process page table look-at might be the solution to find the virtual address map to physical address. Were there any ways to do page table look-at? Or othere ways can fit the verify experiment?
thanks in advance!
The dynamic loader uses mmap(2) with MAP_PRIVATE and appropriate permissions. You can see what it does exactly by running a command from strace -e file,mmap. For instance:
strace -e file,mmap ls
All the magic comes from mmap(2). mmap(2) creates mappings in the calling process, they are usually backed either by a file or by swap (anonymous mappings). In a file-backed mapping, MAP_PRIVATE means that writes to the memory don't update the file, and cause that page to be backed by swap from that point on (copy-on-write).
The dynamic loader gets the info it needs from ELF's program headers, which you can view with:
readelf -l libfoo.so
From these, the dynamic loader determines what to map as code, read-only data, data and bss (zero-filled segment with zero size in file, non-zero size in memory, and a name only matched in crypticness by Lisp's car and cdr).
So, in fact, code and also data is shared, until a write causes copy-on-write. That is why marking constant data as constant is a potentially important space optimization (see DSO howto).
You can get more info on the mmap(2) manpage, and in Documentation/nommu-mmap.txt (the MMU case, no-MMU is for embedded devices, like ADSL routers and the Nintendo DS).
Shared libraries just a particular use of mapped files.
The address which a file is mapped at in a process's address space has nothing to do with whether it is shared or not.
Pages can be shared even if they are mapped at different addresses.
To find out if pages are being shared, do the following:
Find the address that the file(s) are mapped at by examining /proc/pid/maps
There is a tool which extracts data from /proc/pid/pagemap - find it and use it. This gives you info as to exactly which page(s) of a mapping are present and what physical location they are at
If two processes have a page mapped in at the same physical address, it is of course, shared.