Linux: update embedded resource from executable
Nothing special and nothing hard at all. I'll give you correct sequence below, but first let me to correct slightly your embedding method. Lets not use objcopy
explicitly, lets use GNU LD instead to got correct entry inside ELF file.
Lets begin. This is test-emb.c
file:
#include <stdio.h>
extern unsigned char data[] asm("_binary_data_txt_start");
int
main (void)
{
fprintf(stderr, "%u, %u, %u\n", data[0] - '0', data[1] - '0', data[2] - '0');
return 0;
}
This is resource called data.txt
12345678
This is another resource called newdata.txt
98765432
Now compile and link:
$ gcc test-emb.c -c -m32
$ gcc -o test-emb test-emb.o -Wl,--format=binary -Wl,data.txt -Wl,--format=default -m32
Try:
$ ./test-emb
1, 2, 3
Now start dancing. Step one: determine logical and physical address of data section:
$ readelf -S test-emb | grep "\.data" | awk '{print $4}'
080496b8
$ readelf -S test-emb | grep "\.data" | awk '{print $5}'
0006b8
Step two: start and size fo binary data:
$ readelf -s test-emb | grep _binary_data_txt_start | awk '{print $2}'
080496c0
$readelf -s test-emb | grep _binary_data_txt_size | awk '{print $2}'
00000009
Step three: doing math. We do need: find offset of binary data in data, and convert it to physical starting point:
$ echo $((0x080496c0 - 0x080496b8))
8
echo $((0x0006b8 + 8))
1728
Step four: actual replacement (count value is binary data size, taht is 9):
cat newdata.txt | dd of=test-emb bs=1 seek=1728 count=9 conv=notrunc
Now check again:
$ ./test-emb
9, 8, 7
Everything works. You may easily fold this method into script, not harder in use, that UpdateResource under Windows, but I want to give you understanding of how things are going on.
Is there any standard way of embedding resources into Linux executable image?
Make yourself an assembler file, blob.S:
.global blob
.global blob_size
.section .rodata
blob:
.incbin "blob.bin"
1:
blob_size:
.int 1b - blob
Compile with gcc -c blob.S -o blob.o
The blob can now be accessed from within your C program with:
extern uint8_t blob[];
extern int blob_size;
Using a bin2c converter usually works fine, but if the blob is large, the incbin solution is much faster, and uses much less memory (compile time)
Performance of embedding resource files into executable
The disadvantage to this resource allocation method is that all resources will be present in virtual memory for the entire duration of your application.
For example, if you have 10 levels in your game, using a more common file-based storage solution you would only load the data for whichever level you are going to play. By loading all the game data at runtime you are allocating more RAM than necessary. A solution which uses an optimally minimal amount of RAM would only load the resources it needs for the duration it needs them.
However, if you were to use a file-based storage solution for your resources and load them all at the start of execution your RAM usage would be the same as the statically allocated resource method.
Also, if your target machine is a simple game console that does not do multitasking then you are usually free to use the available resources in whatever means suits you the best. There is no requirement to "play nice" as there's typically only one game running at a time.
If you're dealing with a few megabytes on a modern system the penalty is negligible, but the performance penalty when you get into multiple gigabytes of data is that you will be creating an unnecessary strain on the available memory resources of the system.
edit: be sure to see points raised in the comments
Embedding resources in executable using GCC
There are a couple possibilities:
use ld's capability to turn any file into an object (Embedding binary blobs using gcc mingw):
ld -r -b binary -o binary.o foo.bar # then link in binary.o
use a
bin2c
/bin2h
utility to turn any file into an array of bytes (Embed image in code, without using resource section or external images)
Update: Here's a more complete example of how to use data bound into the executable using ld -r -b binary
:
#include <stdio.h>
// a file named foo.bar with some example text is 'imported' into
// an object file using the following command:
//
// ld -r -b binary -o foo.bar.o foo.bar
//
// That creates an bject file named "foo.bar.o" with the following
// symbols:
//
// _binary_foo_bar_start
// _binary_foo_bar_end
// _binary_foo_bar_size
//
// Note that the symbols are addresses (so for example, to get the
// size value, you have to get the address of the _binary_foo_bar_size
// symbol).
//
// In my example, foo.bar is a simple text file, and this program will
// dump the contents of that file which has been linked in by specifying
// foo.bar.o as an object file input to the linker when the progrma is built
extern char _binary_foo_bar_start[];
extern char _binary_foo_bar_end[];
int main(void)
{
printf( "address of start: %p\n", &_binary_foo_bar_start);
printf( "address of end: %p\n", &_binary_foo_bar_end);
for (char* p = _binary_foo_bar_start; p != _binary_foo_bar_end; ++p) {
putchar( *p);
}
return 0;
}
Update 2 - Getting the resource size: I could not read the _binary_foo_bar_size correctly. At runtime, gdb shows me the right size of the text resource by using display (unsigned int)&_binary_foo_bar_size
. But assigning this to a variable gave always a wrong value. I could solve this issue the following way:
unsigned int iSize = (unsigned int)(&_binary_foo_bar_end - &_binary_foo_bar_start)
It is a workaround, but it works good and is not too ugly.
QT Applications - Replacing embedded resources
This answer is specific for Qt's resource system (.qrc, rcc).
From the docs:
Currently, Qt always stores the data directly in the executable, even on Windows, macOS, and iOS, where the operating system provides native support for resources. This might change in a future Qt release.
So yes, the Qt resources are contained in the binary.
rcc
'ing a .qrc file yields a .cpp file containing (mainly) simple char arrays which represent resource data, the resource names and some other metadata.
Compiling such a .cpp file creates byte fields in the binary.
You can alter such resources within a binary, but only in very limited ways.
For starters, if the binary contains any kind of self-check (like hashing the data section and comparing it to some pre-calculated hash), you will not be able to change the data in a reasonable way.
If your data doesn't have the same byte length as the original data, you can't simply replace it because it would alter the internal layout of the binary and invalidate relative addresses.
In case of replacing with shorter strings you might get away with zero-padding at the end.
Resources are compressed by default (in the ZIP format). It is possible to turn off compression.
- If compression was turned on during compilation (which you don't control, as it seems), you'd need to create new data which compresses to the same length as the original.
Embedding a filesystem in an executable?
There exist so-called virtual file system implementations, which were designed with custom storage in mind. To name a few: our Solid File System, CodeBase File System, Single File System by AidAim.
Most of them use files as the container, some (eg. our SolFS) let you have container in custom places and access it via callbacks.
Depending on practical requirements you can use ZIP or even TAR format as well.
If you want to expose the filesystem contained in your executable to the OS so that other applications could read it, then one of our virtual storage solutions (CallbackDisk or Callback File System) will do the job for you on Windows. On Linux and MacOS X there exist other ways to do this, including FUSE and MacFUSE libraries (analogs to our CBFS).
put together all assemblies and use it as embedded resource in exe
I solved this issue. When the host app runs and doesn't find required assembly, it calls AssemblyResolve
event. So, I have to use event handler called MainResolver
to load MyAssembly.dll
. Then before using methods of MyAssembly.dll
, it's necessary to remove it from AssemblyResolve
, because the app tries to resolve dependencies using ResolveEventHandler
in order which they were added (It calls MainResolver
and then Resolver
). As a result the host app fails, because it can't find required assemblies in MainResolver
. The solution is to reorder ResolveEventHandler
or remove MainResolver
from AssemblyResolve
after it was called. I think that exclude useless handler is easier.
So, I don't need to change anything in MyClass
. Everything I need is to add following code in host app before I create instance of MyClass
.
static MyApp(){
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(MainResolver);
}
static void main(string[] args){
//remove MainResolver
AppDomain.CurrentDomain.AssemblyResolve -= MainResolver;
MyClass my = new MyClass();
my.DoWork();
}
Now it works like a charm!
Related Topics
What Does "Private_Dirty" Memory Mean in Smaps
How to Launch a Job in a Shell Which Will Persist Even If The Shell Which Launches It Terminates
Cron Expression to Run on Different Days for Different Months
Cpu Utilization High for Sleeping Processes
How to Write Kernel Space Memory (Physical Address) to a File Using O_Direct
Replace Forward Slash with Double Backslash Enclosed in Double Quotes
Is Visual Basic Supported by .Net Core on Linux
How to Package Mono Applications for Debian/Ubuntu
Building Helloworld C++ Program in Linux with Ncurses
Linux: Move 1 Million Files into Prefix-Based Created Folders
In Bash, How to Expand Variables Twice in Double Quotes
Linux: Update Embedded Resource from Executable
How to Create Ansible Playbook to Obtain Os Versions of The Remote Hosts
How to Redirect Entire Output of Spark-Submit to a File
Tickless Kernel, Isolcpus,Nohz_Full,And Rcu_Nocbs