Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions crates/rk/src/sections.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,19 @@ const INLINED: &[(&str, u64)] = &[
/// into `vmlinux.o`, and 6.1 writes them into every object.
const SITES: &[&str] = &["__mcount_loc", "__patchable_function_entries"];

/// The sections objtool writes into an object, which are left out of the sections an object has
/// for the same reason they are left out of [`SITES`]: whether one is there follows from the code,
/// a `.retpoline_sites` from an indirect call and a `.return_sites` from a `ret`.
const OBJTOOL: &[&str] = &[
".static_call_sites",
".retpoline_sites",
".return_sites",
".call_sites",
".ibt_endbr_seal",
".orc_unwind",
".orc_unwind_ip",
];

/// Prefixes after which `-ffunction-sections` and `-fdata-sections` put a symbol name, with the
/// kernel's own names that start the same way. The kernel writes its own sections with two dots,
/// `.data..percpu`, so a single dot and a name is the compiler's.
Expand Down Expand Up @@ -406,6 +419,7 @@ pub fn read(data: &[u8]) -> Result<Object, String> {
)
|| name.starts_with(".debug")
|| name.starts_with(".rela")
|| OBJTOOL.contains(&name)
{
continue;
}
Expand Down Expand Up @@ -859,6 +873,27 @@ mod tests {
assert_eq!(unnumbered(".7"), ".7");
}

#[test]
fn a_list_objtool_writes_is_not_a_section_the_object_has() {
let with = |extra: &[&str]| {
let mut b = Builder::new();
b.function("f", &[0xc3]);
for name in extra {
b.section(name, &[0; 4]);
}
read(&b.bytes()).unwrap()
};
let reference: Inventory = [("a.o".to_string(), with(&[]))].into();
let other: Inventory = [(
"a.o".to_string(),
with(&[".retpoline_sites", ".return_sites"]),
)]
.into();
assert!(compare(&reference, &other).clean());
let other: Inventory = [("a.o".to_string(), with(&[".init.rodata"]))].into();
assert!(!compare(&reference, &other).clean());
}

fn object(sites: usize, jump: usize, license: &str) -> Vec<u8> {
let mut b = Builder::new();
let f = b.function("f", &[0x90; 8]);
Expand Down
2 changes: 1 addition & 1 deletion docs/plan/09-objtool-linking-and-images.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ This is the check that would have caught CCC's x86 failure, its 40,000 undefined
| set of section names, ignoring per-function names under `-ffunction-sections` | equal. Extra or missing names are failures |
| entry counts of the kernel's tables: `__ksymtab`, `__ksymtab_gpl`, `__kcrctab*`, `.init.setup`, `.initcall*.init`, `__param`, `.con_initcall.init`, `__tracepoints*`, `_ftrace_events`, `__syscalls_metadata`, `.BTF_ids` | equal per object |
| the call-site lists the compiler writes: `__mcount_loc`, `__patchable_function_entries` | equal per function that exists in both, since they depend on inlining decisions |
| the lists objtool writes: `.static_call_sites`, `.retpoline_sites`, `.return_sites`, `.call_sites`, `.ibt_endbr_seal`, `.orc_unwind_ip` | not counted. objtool builds them from the code, an ORC entry for every stack change and a return site for every `ret`, so the counts are each compiler's own instructions. `rk objtool-report` is the check for them. Before IBT, as in 6.1, every object has them, and from then on only `vmlinux.o` does |
| the lists objtool writes: `.static_call_sites`, `.retpoline_sites`, `.return_sites`, `.call_sites`, `.ibt_endbr_seal`, `.orc_unwind`, `.orc_unwind_ip` | not counted, and not in the sections an object is compared on either. objtool builds them from the code, an ORC entry for every stack change and a return site for every `ret`, so the counts are each compiler's own instructions. `rk objtool-report` is the check for them. Before IBT, as in 6.1, every object has them, and from then on only `vmlinux.o` does |
| the tables written by the code they describe: `__jump_table`, `__bug_table`, `__ex_table`, `.altinstructions` | the same set of distinct sites per object. Every inlined copy of a `static_branch_unlikely` or a `WARN_ON` adds an entry, so the counts follow the inliner like the call-site lists do. A site is what the entry says apart from code addresses: the key and branch of a jump label, the format, file, line and flags of a bug, the fixup type of an exception entry without its register, and the CPU feature of an alternative |
| `Module.symvers`: exported symbols, their namespaces, and CRCs | equal |
| `System.map` global symbol set | equal, apart from compiler-generated local suffixes |
Expand Down
43 changes: 43 additions & 0 deletions sections-divergences.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ only = "either"
item = ".rodata"
reason = "a switch turned into a lookup table, or a constant local array kept in memory, which follows each compiler's own switch conversion and scalar replacement"

[[divergence]]
what = "sections"
only = "either"
item = ".init.rodata"
reason = "a constant local array in an __init function kept in memory, such as the ids in add_rtc_cmos on 6.1, which gcc removes after it unrolls the loop over it and folds the loads"

[[divergence]]
what = "sections"
only = "either"
Expand Down Expand Up @@ -209,3 +215,40 @@ object = "kernel/signal.o"
only = "reference"
item = '4="include/linux/thread_info.h" f9000309'
reason = "WARN_ON_ONCE(bytes > INT_MAX) in check_copy_size, which lives in thread_info.h on 6.12, with the same bounded copies as on 7.2.8"

# 6.1.188. The sites carry no format string there either, and the lines are 6.1's.

[[divergence]]
what = "__bug_table"
object = "drivers/char/random.o"
only = "reference"
item = '4="drivers/char/random.c" fe000000'
reason = "BUG_ON(random_data_len > 32) in crng_fast_key_erasure, with the same bound as on 7.2.8"

[[divergence]]
what = "__bug_table"
object = "drivers/char/random.o"
only = "reference"
item = '4="drivers/char/random.c" 29010000'
reason = "BUG_ON(random_data_len > 32) in crng_make_state, with the same bound as on 7.2.8"

[[divergence]]
what = "__bug_table"
object = "fs/ext4/extents.o"
only = "reference"
item = '4="fs/ext4/extents.c" 750c0000'
reason = "the BUG_ON in ext4_split_extent_at for both DATA_VALID flags at once, where ext4_split_extent passes at most one of them and the other two callers pass only the MARK_UNWRIT flags"

[[divergence]]
what = "__bug_table"
object = "fs/ext4/page-io.o"
only = "reference"
item = '4="fs/ext4/page-io.c" e6000109'
reason = "WARN_ON(!(io_end->flag & EXT4_IO_END_UNWRITTEN)) in ext4_add_complete_io, whose only caller returns early when the flag is clear, as on 6.12"

[[divergence]]
what = "__bug_table"
object = "kernel/signal.o"
only = "reference"
item = '4="include/linux/thread_info.h" e9000309'
reason = "WARN_ON_ONCE(bytes > INT_MAX) in check_copy_size, with the same bounded copies as on 6.12"
Loading