I would like to be able to dynamically change the executable code within a library I am using. Essentially, I would like to dynamically NOP out certain functions if they are not needed.
However, the .text section of the library I am using is not-writable (as is the case for most programs). I have the source code of the library and so would like to use GCC to compile it as writable.
Is there a way to do this?
The text segment defines a read-only executable loadable segment that accepts allocable, non-writable sections. This includes executable code, read-only data needed by the program, and read-only data produced by the link-editor for use by the runtime linker such as the dynamic symbol table.
GCC stands for GNU Compiler Collections which is used to compile mainly C and C++ language. It can also be used to compile Objective C and Objective C++.
Whenever we compile any code, the output that we get is an executable file, which we generally don't bother about. We execute it on our desired target. If it is an embedded system, we flash it to the target device and run it. Usually, this executable file is the ELF (Executable and Linkable Format) file.
Linking is performed when the input file are object files " .o " (instead of source file " . cpp " or " . c "). GCC uses a separate linker program (called ld.exe ) to perform the linking.
In the general sense, mprotect
is the perferred choice (on POSIX conforming systems) under sys/mman.h
(check http://linux.die.net/man/2/mprotect). Simply get the address and system page count of the executable section of your process and call mprotect
to request permission permissions; write to it; then, call mprotect
again to release write permission.
However, if this is meant to be on low-level routines where speed is of absolute importance (or mprotect
is not available) then you'll want to compile the library with its .text
section writable as calling mprotect
most likely issues a Translation Lookaside Buffer (TLB) flush that (especially in a multi-processor environment) can and will cause a bottleneck. If the specific system is using hardware protection via paging (which nearly all are now) then the only way to change the protection is by doing a TLB flush which must be executed on every referenced page, referenced page table (group of pages), referenced page directory (group of page tables) and every processor. To top it off, this must be executed in ring 0 which requires a syscall which just puts the cherry on top for overhead.
In the latter case, the easiest solution would be to compile the library normally and then objcopy
it with --writable-text
(as mentioned by ggiroux).
Another solution would be to define the linker map file linker.ld
yourself. Then you may specify permissions of any section explicitly. Its not too complicated; if system-dependent. Refer to documentation at http://www.math.utah.edu/docs/info/ld_3.html. You could also look at your system provided linker.ld
file and modify it from there. Passing -Wl,--verbose
to gcc will instruct the linker to spit out all relevant files (including its default linker.ld) in which you could then modify the permissions of the .text section and recompile the library (forevermore) using the new linker.ld
file.
To summarize, my recommendation would be to do as the last paragraph states and compile your library with a slightly modified linker script.
The easiest way i found (binutils 2.22) is to link with -N That can be passes to gcc with gcc -XN
Try objcopy --writable-text
on the compiled library, according to the documentation it should make .text writable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With