All linux binary applications have a common ELF format (Executable and Linking Format). This format consist of header and variouse sections (see ELF Specification). The ELF allows you to attach custom sections with some extra user-data. It means that you can hide some usefull information inside a binary file (like library for example). Why you would want to use such thing? Well, for many reasons. As for an example I will describe my favourite case. I frequently use custom sections to inject some extra information from CI/CD into binary programs for further identification on testbed/production/devices. I usually use custom flags to pass such info in a compile time. Like in a simplified example bellow.
Example Code
This C++ code be easily ported to ANSI C.
#include <iostream>
#define STRINGIZER(arg) #arg
#define STRVAL(v) STRINGIZER(v)
constexpr const char commit_id[] __attribute__((section("mysection"))) = "commit-id=" STRVAL(COMMIT_ID);
constexpr const char build_time[] __attribute__((section("mysection"))) = "build-time=" STRVAL(BUILD_TIME);
int main(int argc, char *argv[])
{
std::cout << "Hello, World!" << std::endl;
return (0);
}
Compile and read extra data
$ g++ --std=c++2a -Werror -pedantic -DCOMMIT_ID=123 -DBUILD_TIME=321 -o main ./main.cpp
$ readelf -p mysection ./main
String dump of section 'mysection':
[ 0] commit-id: 123
[ 10] build-time: 321
Some final words
- The important thing is that your user-section with a custom name points to a block of text, so it can be even a json content.
- In an ELF specification you can find information that user-section should not start with a dott (it’s reserved for inner use).
- It’s not the only way how you can attach custom sections. You can also use objcopy to inject extra user-data.