Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

objtool: Refactor add_jump_destinations()

The add_jump_destinations() logic is a bit weird and convoluted after
being incrementally tweaked over the years. Refactor it to hopefully be
more logical and straightforward.

Acked-by: Petr Mladek <pmladek@suse.com>
Tested-by: Joe Lawrence <joe.lawrence@redhat.com>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>

+106 -120
+104 -118
tools/objtool/check.c
··· 1423 1423 } 1424 1424 1425 1425 static bool is_first_func_insn(struct objtool_file *file, 1426 - struct instruction *insn, struct symbol *sym) 1426 + struct instruction *insn) 1427 1427 { 1428 - if (insn->offset == sym->offset) 1428 + struct symbol *func = insn_func(insn); 1429 + 1430 + if (!func) 1431 + return false; 1432 + 1433 + if (insn->offset == func->offset) 1429 1434 return true; 1430 1435 1431 1436 /* Allow direct CALL/JMP past ENDBR */ ··· 1438 1433 struct instruction *prev = prev_insn_same_sym(file, insn); 1439 1434 1440 1435 if (prev && prev->type == INSN_ENDBR && 1441 - insn->offset == sym->offset + prev->len) 1436 + insn->offset == func->offset + prev->len) 1442 1437 return true; 1443 1438 } 1444 1439 ··· 1446 1441 } 1447 1442 1448 1443 /* 1449 - * A sibling call is a tail-call to another symbol -- to differentiate from a 1450 - * recursive tail-call which is to the same symbol. 1451 - */ 1452 - static bool jump_is_sibling_call(struct objtool_file *file, 1453 - struct instruction *from, struct instruction *to) 1454 - { 1455 - struct symbol *fs = from->sym; 1456 - struct symbol *ts = to->sym; 1457 - 1458 - /* Not a sibling call if from/to a symbol hole */ 1459 - if (!fs || !ts) 1460 - return false; 1461 - 1462 - /* Not a sibling call if not targeting the start of a symbol. */ 1463 - if (!is_first_func_insn(file, to, ts)) 1464 - return false; 1465 - 1466 - /* Disallow sibling calls into STT_NOTYPE */ 1467 - if (is_notype_sym(ts)) 1468 - return false; 1469 - 1470 - /* Must not be self to be a sibling */ 1471 - return fs->pfunc != ts->pfunc; 1472 - } 1473 - 1474 - /* 1475 1444 * Find the destination instructions for all jumps. 1476 1445 */ 1477 1446 static int add_jump_destinations(struct objtool_file *file) 1478 1447 { 1479 - struct instruction *insn, *jump_dest; 1448 + struct instruction *insn; 1480 1449 struct reloc *reloc; 1481 - struct section *dest_sec; 1482 - unsigned long dest_off; 1483 1450 1484 1451 for_each_insn(file, insn) { 1485 1452 struct symbol *func = insn_func(insn); 1453 + struct instruction *dest_insn; 1454 + struct section *dest_sec; 1455 + struct symbol *dest_sym; 1456 + unsigned long dest_off; 1457 + 1458 + if (!is_static_jump(insn)) 1459 + continue; 1486 1460 1487 1461 if (insn->jump_dest) { 1488 1462 /* ··· 1470 1486 */ 1471 1487 continue; 1472 1488 } 1473 - if (!is_static_jump(insn)) 1474 - continue; 1475 1489 1476 1490 reloc = insn_reloc(file, insn); 1477 1491 if (!reloc) { 1478 1492 dest_sec = insn->sec; 1479 1493 dest_off = arch_jump_destination(insn); 1480 - } else if (is_sec_sym(reloc->sym)) { 1481 - dest_sec = reloc->sym->sec; 1482 - dest_off = arch_insn_adjusted_addend(insn, reloc); 1483 - } else if (reloc->sym->retpoline_thunk) { 1484 - if (add_retpoline_call(file, insn)) 1485 - return -1; 1486 - continue; 1487 - } else if (reloc->sym->return_thunk) { 1488 - add_return_call(file, insn, true); 1489 - continue; 1490 - } else if (func) { 1491 - /* 1492 - * External sibling call or internal sibling call with 1493 - * STT_FUNC reloc. 1494 - */ 1495 - if (add_call_dest(file, insn, reloc->sym, true)) 1496 - return -1; 1497 - continue; 1498 - } else if (reloc->sym->sec->idx) { 1499 - dest_sec = reloc->sym->sec; 1500 - dest_off = reloc->sym->sym.st_value + 1501 - arch_insn_adjusted_addend(insn, reloc); 1494 + dest_sym = dest_sec->sym; 1502 1495 } else { 1503 - /* non-func asm code jumping to another file */ 1504 - continue; 1496 + dest_sym = reloc->sym; 1497 + if (is_undef_sym(dest_sym)) { 1498 + if (dest_sym->retpoline_thunk) { 1499 + if (add_retpoline_call(file, insn)) 1500 + return -1; 1501 + continue; 1502 + } 1503 + 1504 + if (dest_sym->return_thunk) { 1505 + add_return_call(file, insn, true); 1506 + continue; 1507 + } 1508 + 1509 + /* External symbol */ 1510 + if (func) { 1511 + /* External sibling call */ 1512 + if (add_call_dest(file, insn, dest_sym, true)) 1513 + return -1; 1514 + continue; 1515 + } 1516 + 1517 + /* Non-func asm code jumping to external symbol */ 1518 + continue; 1519 + } 1520 + 1521 + dest_sec = dest_sym->sec; 1522 + dest_off = dest_sym->offset + arch_insn_adjusted_addend(insn, reloc); 1505 1523 } 1506 1524 1507 - jump_dest = find_insn(file, dest_sec, dest_off); 1508 - if (!jump_dest) { 1525 + dest_insn = find_insn(file, dest_sec, dest_off); 1526 + if (!dest_insn) { 1509 1527 struct symbol *sym = find_symbol_by_offset(dest_sec, dest_off); 1510 1528 1511 1529 /* 1512 - * This is a special case for retbleed_untrain_ret(). 1513 - * It jumps to __x86_return_thunk(), but objtool 1514 - * can't find the thunk's starting RET 1515 - * instruction, because the RET is also in the 1516 - * middle of another instruction. Objtool only 1517 - * knows about the outer instruction. 1530 + * retbleed_untrain_ret() jumps to 1531 + * __x86_return_thunk(), but objtool can't find 1532 + * the thunk's starting RET instruction, 1533 + * because the RET is also in the middle of 1534 + * another instruction. Objtool only knows 1535 + * about the outer instruction. 1518 1536 */ 1519 1537 if (sym && sym->embedded_insn) { 1520 1538 add_return_call(file, insn, false); ··· 1524 1538 } 1525 1539 1526 1540 /* 1527 - * GCOV/KCOV dead code can jump to the end of the 1528 - * function/section. 1541 + * GCOV/KCOV dead code can jump to the end of 1542 + * the function/section. 1529 1543 */ 1530 1544 if (file->ignore_unreachables && func && 1531 1545 dest_sec == insn->sec && 1532 1546 dest_off == func->offset + func->len) 1533 1547 continue; 1534 1548 1535 - ERROR_INSN(insn, "can't find jump dest instruction at %s+0x%lx", 1536 - dest_sec->name, dest_off); 1549 + ERROR_INSN(insn, "can't find jump dest instruction at %s", 1550 + offstr(dest_sec, dest_off)); 1537 1551 return -1; 1538 1552 } 1539 1553 1540 - /* 1541 - * An intra-TU jump in retpoline.o might not have a relocation 1542 - * for its jump dest, in which case the above 1543 - * add_{retpoline,return}_call() didn't happen. 1544 - */ 1545 - if (jump_dest->sym && jump_dest->offset == jump_dest->sym->offset) { 1546 - if (jump_dest->sym->retpoline_thunk) { 1547 - if (add_retpoline_call(file, insn)) 1548 - return -1; 1549 - continue; 1550 - } 1551 - if (jump_dest->sym->return_thunk) { 1552 - add_return_call(file, insn, true); 1553 - continue; 1554 - } 1554 + if (!dest_sym || is_sec_sym(dest_sym)) { 1555 + dest_sym = dest_insn->sym; 1556 + if (!dest_sym) 1557 + goto set_jump_dest; 1555 1558 } 1556 1559 1557 - /* 1558 - * Cross-function jump. 1559 - */ 1560 - 1561 - if (func && insn_func(jump_dest) && !func->cold && 1562 - insn_func(jump_dest)->cold) { 1563 - 1564 - /* 1565 - * For GCC 8+, create parent/child links for any cold 1566 - * subfunctions. This is _mostly_ redundant with a 1567 - * similar initialization in read_symbols(). 1568 - * 1569 - * If a function has aliases, we want the *first* such 1570 - * function in the symbol table to be the subfunction's 1571 - * parent. In that case we overwrite the 1572 - * initialization done in read_symbols(). 1573 - * 1574 - * However this code can't completely replace the 1575 - * read_symbols() code because this doesn't detect the 1576 - * case where the parent function's only reference to a 1577 - * subfunction is through a jump table. 1578 - */ 1579 - func->cfunc = insn_func(jump_dest); 1580 - insn_func(jump_dest)->pfunc = func; 1581 - } 1582 - 1583 - if (jump_is_sibling_call(file, insn, jump_dest)) { 1584 - /* 1585 - * Internal sibling call without reloc or with 1586 - * STT_SECTION reloc. 1587 - */ 1588 - if (add_call_dest(file, insn, insn_func(jump_dest), true)) 1560 + if (dest_sym->retpoline_thunk && dest_insn->offset == dest_sym->offset) { 1561 + if (add_retpoline_call(file, insn)) 1589 1562 return -1; 1590 1563 continue; 1591 1564 } 1592 1565 1593 - insn->jump_dest = jump_dest; 1566 + if (dest_sym->return_thunk && dest_insn->offset == dest_sym->offset) { 1567 + add_return_call(file, insn, true); 1568 + continue; 1569 + } 1570 + 1571 + if (!insn->sym || insn->sym == dest_insn->sym) 1572 + goto set_jump_dest; 1573 + 1574 + /* 1575 + * Internal cross-function jump. 1576 + */ 1577 + 1578 + /* 1579 + * For GCC 8+, create parent/child links for any cold 1580 + * subfunctions. This is _mostly_ redundant with a 1581 + * similar initialization in read_symbols(). 1582 + * 1583 + * If a function has aliases, we want the *first* such 1584 + * function in the symbol table to be the subfunction's 1585 + * parent. In that case we overwrite the 1586 + * initialization done in read_symbols(). 1587 + * 1588 + * However this code can't completely replace the 1589 + * read_symbols() code because this doesn't detect the 1590 + * case where the parent function's only reference to a 1591 + * subfunction is through a jump table. 1592 + */ 1593 + if (func && dest_sym->cold) { 1594 + func->cfunc = dest_sym; 1595 + dest_sym->pfunc = func; 1596 + goto set_jump_dest; 1597 + } 1598 + 1599 + if (is_first_func_insn(file, dest_insn)) { 1600 + /* Internal sibling call */ 1601 + if (add_call_dest(file, insn, dest_sym, true)) 1602 + return -1; 1603 + continue; 1604 + } 1605 + 1606 + set_jump_dest: 1607 + insn->jump_dest = dest_insn; 1594 1608 } 1595 1609 1596 1610 return 0;
+2 -2
tools/objtool/include/objtool/elf.h
··· 181 181 return elf_addr_size(elf) == 4 ? R_TEXT32 : R_TEXT64; 182 182 } 183 183 184 - static inline bool sym_has_sec(struct symbol *sym) 184 + static inline bool is_undef_sym(struct symbol *sym) 185 185 { 186 - return sym->sec->idx; 186 + return !sym->sec->idx; 187 187 } 188 188 189 189 static inline bool is_null_sym(struct symbol *sym)