mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 20:51:44 +00:00
1c34496e58
Replace the instruction::list by allocating instructions in arrays of 256 entries and stringing them together by (amortized) find_insn(). This shrinks instruction by 16 bytes and brings it down to 128. struct instruction { - struct list_head list; /* 0 16 */ - struct hlist_node hash; /* 16 16 */ - struct list_head call_node; /* 32 16 */ - struct section * sec; /* 48 8 */ - long unsigned int offset; /* 56 8 */ - /* --- cacheline 1 boundary (64 bytes) --- */ - long unsigned int immediate; /* 64 8 */ - unsigned int len; /* 72 4 */ - u8 type; /* 76 1 */ - - /* Bitfield combined with previous fields */ + struct hlist_node hash; /* 0 16 */ + struct list_head call_node; /* 16 16 */ + struct section * sec; /* 32 8 */ + long unsigned int offset; /* 40 8 */ + long unsigned int immediate; /* 48 8 */ + u8 len; /* 56 1 */ + u8 prev_len; /* 57 1 */ + u8 type; /* 58 1 */ + s8 instr; /* 59 1 */ + u32 idx:8; /* 60: 0 4 */ + u32 dead_end:1; /* 60: 8 4 */ + u32 ignore:1; /* 60: 9 4 */ + u32 ignore_alts:1; /* 60:10 4 */ + u32 hint:1; /* 60:11 4 */ + u32 save:1; /* 60:12 4 */ + u32 restore:1; /* 60:13 4 */ + u32 retpoline_safe:1; /* 60:14 4 */ + u32 noendbr:1; /* 60:15 4 */ + u32 entry:1; /* 60:16 4 */ + u32 visited:4; /* 60:17 4 */ + u32 no_reloc:1; /* 60:21 4 */ - u16 dead_end:1; /* 76: 8 2 */ - u16 ignore:1; /* 76: 9 2 */ - u16 ignore_alts:1; /* 76:10 2 */ - u16 hint:1; /* 76:11 2 */ - u16 save:1; /* 76:12 2 */ - u16 restore:1; /* 76:13 2 */ - u16 retpoline_safe:1; /* 76:14 2 */ - u16 noendbr:1; /* 76:15 2 */ - u16 entry:1; /* 78: 0 2 */ - u16 visited:4; /* 78: 1 2 */ - u16 no_reloc:1; /* 78: 5 2 */ + /* XXX 10 bits hole, try to pack */ - /* XXX 2 bits hole, try to pack */ - /* Bitfield combined with next fields */ - - s8 instr; /* 79 1 */ - struct alt_group * alt_group; /* 80 8 */ - struct instruction * jump_dest; /* 88 8 */ - struct instruction * first_jump_src; /* 96 8 */ + /* --- cacheline 1 boundary (64 bytes) --- */ + struct alt_group * alt_group; /* 64 8 */ + struct instruction * jump_dest; /* 72 8 */ + struct instruction * first_jump_src; /* 80 8 */ union { - struct symbol * _call_dest; /* 104 8 */ - struct reloc * _jump_table; /* 104 8 */ - }; /* 104 8 */ - struct alternative * alts; /* 112 8 */ - struct symbol * sym; /* 120 8 */ - /* --- cacheline 2 boundary (128 bytes) --- */ - struct stack_op * stack_ops; /* 128 8 */ - struct cfi_state * cfi; /* 136 8 */ + struct symbol * _call_dest; /* 88 8 */ + struct reloc * _jump_table; /* 88 8 */ + }; /* 88 8 */ + struct alternative * alts; /* 96 8 */ + struct symbol * sym; /* 104 8 */ + struct stack_op * stack_ops; /* 112 8 */ + struct cfi_state * cfi; /* 120 8 */ - /* size: 144, cachelines: 3, members: 28 */ - /* sum members: 142 */ - /* sum bitfield members: 14 bits, bit holes: 1, sum bit holes: 2 bits */ - /* last cacheline: 16 bytes */ + /* size: 128, cachelines: 2, members: 29 */ + /* sum members: 124 */ + /* sum bitfield members: 22 bits, bit holes: 1, sum bit holes: 10 bits */ }; pre: 5:38.18 real, 213.25 user, 124.90 sys, 23449040 mem post: 5:03.34 real, 210.75 user, 88.80 sys, 20241232 mem Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Ingo Molnar <mingo@kernel.org> Acked-by: Josh Poimboeuf <jpoimboe@kernel.org> Tested-by: Nathan Chancellor <nathan@kernel.org> # build only Tested-by: Thomas Weißschuh <linux@weissschuh.net> # compile and run Link: https://lore.kernel.org/r/20230208172245.851307606@infradead.org
153 lines
2.8 KiB
C
153 lines
2.8 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com>
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <subcmd/exec-cmd.h>
|
|
#include <subcmd/pager.h>
|
|
#include <linux/kernel.h>
|
|
|
|
#include <objtool/builtin.h>
|
|
#include <objtool/objtool.h>
|
|
#include <objtool/warn.h>
|
|
|
|
bool help;
|
|
|
|
const char *objname;
|
|
static struct objtool_file file;
|
|
|
|
static bool objtool_create_backup(const char *_objname)
|
|
{
|
|
int len = strlen(_objname);
|
|
char *buf, *base, *name = malloc(len+6);
|
|
int s, d, l, t;
|
|
|
|
if (!name) {
|
|
perror("failed backup name malloc");
|
|
return false;
|
|
}
|
|
|
|
strcpy(name, _objname);
|
|
strcpy(name + len, ".orig");
|
|
|
|
d = open(name, O_CREAT|O_WRONLY|O_TRUNC, 0644);
|
|
if (d < 0) {
|
|
perror("failed to create backup file");
|
|
return false;
|
|
}
|
|
|
|
s = open(_objname, O_RDONLY);
|
|
if (s < 0) {
|
|
perror("failed to open orig file");
|
|
return false;
|
|
}
|
|
|
|
buf = malloc(4096);
|
|
if (!buf) {
|
|
perror("failed backup data malloc");
|
|
return false;
|
|
}
|
|
|
|
while ((l = read(s, buf, 4096)) > 0) {
|
|
base = buf;
|
|
do {
|
|
t = write(d, base, l);
|
|
if (t < 0) {
|
|
perror("failed backup write");
|
|
return false;
|
|
}
|
|
base += t;
|
|
l -= t;
|
|
} while (l);
|
|
}
|
|
|
|
if (l < 0) {
|
|
perror("failed backup read");
|
|
return false;
|
|
}
|
|
|
|
free(name);
|
|
free(buf);
|
|
close(d);
|
|
close(s);
|
|
|
|
return true;
|
|
}
|
|
|
|
struct objtool_file *objtool_open_read(const char *_objname)
|
|
{
|
|
if (objname) {
|
|
if (strcmp(objname, _objname)) {
|
|
WARN("won't handle more than one file at a time");
|
|
return NULL;
|
|
}
|
|
return &file;
|
|
}
|
|
objname = _objname;
|
|
|
|
file.elf = elf_open_read(objname, O_RDWR);
|
|
if (!file.elf)
|
|
return NULL;
|
|
|
|
if (opts.backup && !objtool_create_backup(objname)) {
|
|
WARN("can't create backup file");
|
|
return NULL;
|
|
}
|
|
|
|
hash_init(file.insn_hash);
|
|
INIT_LIST_HEAD(&file.retpoline_call_list);
|
|
INIT_LIST_HEAD(&file.return_thunk_list);
|
|
INIT_LIST_HEAD(&file.static_call_list);
|
|
INIT_LIST_HEAD(&file.mcount_loc_list);
|
|
INIT_LIST_HEAD(&file.endbr_list);
|
|
INIT_LIST_HEAD(&file.call_list);
|
|
file.ignore_unreachables = opts.no_unreachable;
|
|
file.hints = false;
|
|
|
|
return &file;
|
|
}
|
|
|
|
void objtool_pv_add(struct objtool_file *f, int idx, struct symbol *func)
|
|
{
|
|
if (!opts.noinstr)
|
|
return;
|
|
|
|
if (!f->pv_ops) {
|
|
WARN("paravirt confusion");
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* These functions will be patched into native code,
|
|
* see paravirt_patch().
|
|
*/
|
|
if (!strcmp(func->name, "_paravirt_nop") ||
|
|
!strcmp(func->name, "_paravirt_ident_64"))
|
|
return;
|
|
|
|
/* already added this function */
|
|
if (!list_empty(&func->pv_target))
|
|
return;
|
|
|
|
list_add(&func->pv_target, &f->pv_ops[idx].targets);
|
|
f->pv_ops[idx].clean = false;
|
|
}
|
|
|
|
int main(int argc, const char **argv)
|
|
{
|
|
static const char *UNUSED = "OBJTOOL_NOT_IMPLEMENTED";
|
|
|
|
/* libsubcmd init */
|
|
exec_cmd_init("objtool", UNUSED, UNUSED, UNUSED);
|
|
pager_init(UNUSED);
|
|
|
|
objtool_run(argc, argv);
|
|
|
|
return 0;
|
|
}
|