ANNOBIN(1)

πŸ“¦
version 13.31 Β· 3 versions
, in centos-stream 10, centos-stream 9, fedora 44

okay bestie, we're in the annobin(1) manual from the RPM Development Tools crew πŸŽ€ it's giving main character energy, so let's get into it πŸ’–

✨ NAME ✨

annobin - Annobin πŸ¦‹

🌸 SYNOPSIS 🌸

okay this one's literally empty, no cap πŸ’€ nothing to see here

πŸ’… DESCRIPTION πŸ’…

Binary Annotation is a method for recording info about an application inside the application itself 🫢 It's an implementation of the "Watermark" specification, which lives at https://fedoraproject.org/wiki/Toolchain/Watermark 🌈

Okay so, it's mainly about recording security info, but the system can store any kind of data, even stuff that has nothing to do with the app ✨ One of the big goals is being able to say exactly which address range a piece of info is valid for. So for example, you could say a whole program was compiled with -O2 except for one special function that got -O0 instead πŸ‘‘ iconic behavior, honestly.

The range info is super useful because third parties can poke at the binary and check whether it was built consistently πŸ” i.e. there are no gaps in the recorded info, and no sneaky special cases where a required feature wasn't active 😀

The system works by adding special sections to the application. Each one holds an individual piece of info along with the address range where it's valid. (Some serious effort went into storing all this in a reasonably compact format πŸ“)

The info is generated by a plugin attached to the compiler 🧚 The plugin pulls information out of the compiler's internals and records it in the object file(s) being produced.

Note, though: the plugin is just one way of generating the info. Any interested party can create and add info to the object file, as long as they follow the Watermark specification πŸ’œ

The info can be extracted with tools like readelf and objdump 🧐 The annobin package also includes a program called annocheck that can examine this info too. Details on it can be found elsewhere in this documentation πŸ“š

Experience has shown that storing the range info along with the data tends to significantly increase program size 😭 So the system also has an alternative implementation that uses a more compact format, at the cost of dropping the range data πŸ’…

Normally the build system turns on recording of binary annotation notes automatically, so you don't have to do anything πŸ™Œ On Fedora and RHEL based systems, this is handled by the redhat-rpm-config package πŸŽ€

Right now the binary annotations are generated by a plugin to the compiler (GCC, clang or llvm). That means files not compiled by any of these won't gain any annotations πŸ™ˆ There is an optional assembler switch that adds some basic notes if none are present in the input files, though πŸ› 

If the build system you're using doesn't automatically enable the annobin plugin, you can add it to the compiler command line yourself with one of these:

  • -fplugin=annobin β€” for gcc
  • -fplugin=annobin-for-clang β€” for clang
  • -fplugin=annobin-for-llvm β€” for LLVM

You might also need to tell the compiler where to find the plugin with -iplugindir=. Only do this if the plugin is installed somewhere unusual πŸ—Ί

Want to turn off recording? Use one of these:

  • -fplugin-arg-annobin-disable β€” for "gcc"
  • -Xclang -plugin-arg-annobin-disable β€” for "clang" or "llvm"
These must be placed after the -fplugin=annobin option, bestie. Order matters 🚨

On Fedora and RHEL systems, you can disable the plugin entirely for all compilations in a package by adding %undefine _annotated_build to the spec file πŸ’…

The info is stored in the binary in one of two ways: either in ELF Note format inside a special section called .gnu.build.attributes, or as ordinary strings inside a section called .annobin.notes 🧁

The readelf program from the binutils package can extract and display these notes. Adding the --wide option is also helpful ✨

If the info is held in ELF note format, readelf's --notes option will display it. Here's an example of the output:

Displaying notes found in: .gnu.build.attributes
  Owner                        Data size        Description
  GA$<version>3p3              0x00000010       OPEN        Applies to region from 0x8a0 to 0x8c6 (hello.c)
  GA$<tool>gcc 7.2.1 20170915  0x00000000       OPEN        Applies to region from 0x8a0 to 0x8c6
  GA*GOW:0x452b                0x00000000       OPEN        Applies to region from 0x8a0 to 0x8c6
  GA*<stack prot>strong        0x00000000       OPEN        Applies to region from 0x8a0 to 0x8c6
  GA*GOW:0x412b                0x00000010       func        Applies to region from 0x8c0 to 0x8c6 (baz)

This shows all sorts of info 🌸 including that the notes were made using version 3 of the specification, and version 3 of the plugin. The binary was built by gcc version 7.2.1, and the -fstack-protector-strong option was enabled on the command line. The program was compiled with -O2 enabled, except the baz() function, which was compiled with -O0 instead.

The most complicated part of the notes is the owner field πŸ˜΅β€πŸ’« It's used to encode the type of note, its value, and possibly extra data too. The Watermark spec explains the format in detail, but basically it's the letters G and A, then an encoding character (one of *$!+), then a type character, and finally the value.

The notes are always four-byte aligned, even on 64-bit systems. This means consumers of the notes may have to read 8-byte wide values from 4-byte aligned addresses, and producers of the notes may have to generate unaligned relocs when creating them ⚠️

If the info is held as strings, readelf's -p.annobin.notes option will display them. Here's an example of that output:

String dump of section '.annobin.notes':
  [     0]  AV:4.p.1200
  [     c]  RV:running gcc 12.2.1 20221121
  [    2b]  BV:annobin gcc 12.2.1 20221121
  [    4a]  PN:annobin
  [    55]  GW:0x290540
  [    61]  SP:3

✨ OPTIONS ✨

Okay bestie, so the plugin has a whole menu of options πŸ’… You pass them with -fplugin-arg-annobin-<option> if you're on gcc, or -Xclang -plugin-arg-annobin-<option> if you're on clang or llvm πŸ¦‹ They have to come after the plugin is mentioned on the command line, no cap. Also, not every version of the plugin takes every option, so check your version first πŸ™ˆ

You can also slip options in through the ANNOBIN environment variable 🌸 Separate multiple arguments with commas, and anything that needs a value has to use an equals sign. Not a space, not a colon. Equals sign only, periodt.

For backwards compatibility, the LLVM plugin also checks for the ANNOBIN_VERBOSE environment variable, and if it's there, verbose mode turns on ✨

The supported options are:

  • disable, enable β€” Turns the plugin off or on. It's enabled by default, so you only need disable if you want it gone πŸ’–
  • help β€” Prints a list of the supported options to standard output. It does this in addition to whatever else you asked the plugin to do 🧚
  • version β€” Prints the plugin's version to standard output. Same deal, it happens on top of everything else πŸ“
  • verbose β€” Makes the plugin tell you what it's doing. Pass it a second time and it goes very verbose 😭
  • function-verbose β€” Reports when function specific notes get generated. This basically means that function was compiled with different options than the ones turned on globally πŸ‘‘
  • stack-size-notes, no-stack-size-notes β€” Records (or doesn't record) info about how much stack each function needs in the executable. It's off by default because these notes can eat up a LOT of room if your executable has tons of functions πŸ’€
  • stack-threshold=N β€” Only works if stack size notes are being recorded. It sets the minimum to record: functions needing less than N bytes of static stack space get skipped. If you don't set it, N defaults to 1024 ⭐
  • global-file-syms, no-global-file-syms β€” When enabled, this makes globally visible, unique symbols that mark the start and end of the compiled code πŸ¦‹ This is super useful if your program has multiple source files with the same name, or if it links to a library built from source files that share a name with your program. The catch: the unique names are based on the time of the build, so building the same source again gives different symbol names. That breaks the build-id system, which is supposed to identify similar builds made at different times πŸ₯Ί It's disabled by default, and you can turn it back off with no-global-file-syms.
  • attach, no-attach β€” When gcc compiles with -ffunction-sections, each function gets its own section. With attach on, the plugin tries to attach that function section to a group holding the notes and relocations for that function 🫢 That way, if the linker decides to toss the function, it knows to toss the notes and relocations too. attach is the default, and you can disable it with no-attach. Heads up though: if both attach and link-order are disabled, note generation for function sections won't work properly πŸ™ˆ
  • link-order, no-link-order β€” Instead of section groups plus a special assembler directive, the plugin can use the ELF SHF_LINK_ORDER flag. This tells the linker to discard a section if the section it's linked to is also being discarded. Turn it on with link-order πŸ”—
  • rename[=STR] β€” Adds an extra prefix to the symbol names the plugin generates. This lets you run the plugin twice on the same executable, which is handy for debugging and build testing πŸ§ͺ The default prefix is .1, but you can change it by giving this option a string argument.

Note: if you don't use rename, the plugin will try to detect and disable multiple copies of itself. Prior to version 12.72, however, that detection only works reliably if the annobin plugin is the first plugin specified on the gcc command line ⚠️

  • active-checks, no-active-checks β€” By default the plugin warns you if it notices certain preprocessor command line options are missing or misspelt πŸ‘€ active-checks turns those warnings into errors, just like if you'd specified -Werror. no-active-checks shuts the messages up entirely.

Right now, the plugin checks for these:

  • Missing FORTIFY_SOURCE β€” Warns when neither -D_FORTIFY_SOURCE=2 nor -D_FORTIFY_SOURCE=3 is on the command line and -flto is enabled. Normally the annocheck tool would catch this, but LTO compilation hides preprocessor options, so the plugin can't pass that info along. That's why it warns you when _FORTIFY_SOURCE is missing and LTO is on πŸ›‘οΈ
  • -D_FORTIFY_SOURCE typo β€” Warns if -D_FORTIFY_SOURCE is spelt as either -DFORTIFY_SOURCE or -D__FORTIFY_SOURCE 🀭
  • -D_GLIBCXX_ASSERTIONS typo β€” Warns if -D_GLIBCXX_ASSERTIONS is spelt as either -DGLIBCXX_ASSERTIONS or -D__GLIBCXX_ASSERTIONS 🀭

The plugin might get more of these warnings for other missing command line options in the future πŸ‘€

Also, as a workaround for certain tests generated by the autoconf tool, the warning won't be produced if the input source filename starts with conftest.. Autoconf is usually just checking whether a warning would be produced for some other reason, and the annobin warning would get in the way. If active-checks is enabled, though, an error message still gets generated 🫠

  • dynamic-notes, no-dynamic-notes, static-notes, no-static-notes β€” These are deprecated πŸ’€
Deprecated: these options are no longer recommended. Try not to build new stuff around them πŸ™…
  • ppc64-nops, no-ppc64-nops β€” Turns on or off the insertion of NOP instructions in some of the code sections of PowerPC64 binaries 🐘 This is needed to avoid problems with the elflint program, which will complain about binaries built without it. It's enabled by default, but since it makes compiled programs a little bigger, no-ppc64-nops is there if you want to turn it off.
  • note-format="note"|"string" β€” Picks the format used to store the information the plugin generates ✨ The options are:
    • note β€” Stores the info as ELF format notes in the .gnu.build.attributes section.
    • string β€” Stores the info as mergeable strings in the .annobin.notes section.

The default is note πŸ’œ


Copyright (c) 2018-2026 Red Hat. 🌈

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation, with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License" πŸ“œ

And that's the whole page, bestie 🫢 This one comes from annobin-1, dated 2026-02-23. Go forth and compile something iconic πŸ’…βœ¨

πŸ“¦ where this page comes from
  • centos-stream 10: annobin-docs 13.31-1.el10 Β· GPL-3.0-or-later AND LGPL-2.0-or-later AND (GPL-2.0-or-later WITH GCC-exception-2.0) AND (LGPL-2.0-or-later WITH GCC-exception-2.0) AND GFDL-1.3-or-later
  • centos-stream 9: annobin 13.29-1.el9 Β· GPL-3.0-or-later AND LGPL-2.0-or-later AND (GPL-2.0-or-later WITH GCC-exception-2.0) AND (LGPL-2.0-or-later WITH GCC-exception-2.0) AND GFDL-1.3-or-later
  • fedora 44: annobin-docs 13.08-1.fc44 Β· GPL-3.0-or-later AND LGPL-2.0-or-later AND (GPL-2.0-or-later WITH GCC-exception-2.0) AND (LGPL-2.0-or-later WITH GCC-exception-2.0) AND GFDL-1.3-or-later
  • fedora 44: annobin-docs 13.14-1.fc44 Β· GPL-3.0-or-later AND LGPL-2.0-or-later AND (GPL-2.0-or-later WITH GCC-exception-2.0) AND (LGPL-2.0-or-later WITH GCC-exception-2.0) AND GFDL-1.3-or-later
  • πŸ’– girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms