Objtool updates in this cycle were:
- Standardize the crypto asm code so that it looks like compiler-generated code to objtool - so that it can understand it. This enables unwinding from crypto asm code - and also fixes the last known remaining objtool warnings for LTO and more. - x86 decoder fixes: clean up and fix the decoder, and also extend it a bit - Misc fixes and cleanups Signed-off-by: Ingo Molnar <mingo@kernel.org> -----BEGIN PGP SIGNATURE----- iQJFBAABCgAvFiEEBpT5eoXrXCwVQwEKEnMQ0APhK1gFAmCJEOQRHG1pbmdvQGtl cm5lbC5vcmcACgkQEnMQ0APhK1jN0A//dZIR9GPW1cHkPD3Na+lxb+RWgCVnFUgw meLEOum389zWr7S8YmcFpKWLy94f3l24i/e7ufKn6/RMdaQuT6pZUa6teiNPqDKN Qq1v6EX/LT49Q1zh/zCCnKdlmF1t7wDyA1/+HBLnB4YfYEtteEt+p2Apyv4xIHOl xWqaTMFcVR/El9FXSyqRWRR4zuqY0Uatz0fmfo5jmi2xq460k53fQlTLA/0w5Jw0 V3omyA3AYMUW6YlW5TGUINOhyDeAJm4PWl3siSUnSd6t8A/TVs5zpZX15BtseCle 0FRp2SbxOoVkiyo3N3XmkfYYns9+4wK7cr9qja9U9MsSBZJZwaBm2LO/t2WFrAhq 5dkOsoPmpIsjutsQnIhQgtVT9I/A4/u5m5Zi3trlXsBS0XAt/q+2GPfEngFmgb3q nae4rhGUsQ3NTGBiqNuMHQF4yeEvQZ8DCf3ytTz7DjBeiQ9nAtwzbUUGQjYl2mj1 ZPOnl7Xmq/Nyw+AmdpffFPiEUJxqEg9HWjDo7DQATXb3Hw2VJ3cU8jwPRqDDlO10 OB81vysXNGTmhOngHXexxncpmU9gDOIC1imZZpw5lNx4W9Qn20AlGaGAIbqzlfx0 p5VuhkIWCySe1bOZx03xuk7Gq7GBIPPy/a2m204Ftipetlo1HBYwT3KB/wVpHmh7 CSjWgdiW3+k= =poAZ -----END PGP SIGNATURE----- Merge tag 'objtool-core-2021-04-28' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip Pull objtool updates from Ingo Molnar: - Standardize the crypto asm code so that it looks like compiler- generated code to objtool - so that it can understand it. This enables unwinding from crypto asm code - and also fixes the last known remaining objtool warnings for LTO and more. - x86 decoder fixes: clean up and fix the decoder, and also extend it a bit - Misc fixes and cleanups * tag 'objtool-core-2021-04-28' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (24 commits) x86/crypto: Enable objtool in crypto code x86/crypto/sha512-ssse3: Standardize stack alignment prologue x86/crypto/sha512-avx2: Standardize stack alignment prologue x86/crypto/sha512-avx: Standardize stack alignment prologue x86/crypto/sha256-avx2: Standardize stack alignment prologue x86/crypto/sha1_avx2: Standardize stack alignment prologue x86/crypto/sha_ni: Standardize stack alignment prologue x86/crypto/crc32c-pcl-intel: Standardize jump table x86/crypto/camellia-aesni-avx2: Unconditionally allocate stack buffer x86/crypto/aesni-intel_avx: Standardize stack alignment prologue x86/crypto/aesni-intel_avx: Fix register usage comments x86/crypto/aesni-intel_avx: Remove unused macros objtool: Support asm jump tables objtool: Parse options from OBJTOOL_ARGS objtool: Collate parse_options() users objtool: Add --backup objtool,x86: More ModRM sugar objtool,x86: Rewrite ADD/SUB/AND objtool,x86: Support %riz encodings objtool,x86: Simplify register decode ...
This commit is contained in:
commit
03b2cd72aa
@ -2,8 +2,6 @@
|
||||
#
|
||||
# x86 crypto algorithms
|
||||
|
||||
OBJECT_FILES_NON_STANDARD := y
|
||||
|
||||
obj-$(CONFIG_CRYPTO_TWOFISH_586) += twofish-i586.o
|
||||
twofish-i586-y := twofish-i586-asm_32.o twofish_glue.o
|
||||
obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.o
|
||||
|
@ -212,10 +212,6 @@ HashKey_8_k = 16*21 # store XOR of HashKey^8 <<1 mod poly here (for Karatsu
|
||||
#define arg4 %rcx
|
||||
#define arg5 %r8
|
||||
#define arg6 %r9
|
||||
#define arg7 STACK_OFFSET+8*1(%r14)
|
||||
#define arg8 STACK_OFFSET+8*2(%r14)
|
||||
#define arg9 STACK_OFFSET+8*3(%r14)
|
||||
#define arg10 STACK_OFFSET+8*4(%r14)
|
||||
#define keysize 2*15*16(arg1)
|
||||
|
||||
i = 0
|
||||
@ -237,9 +233,6 @@ define_reg j %j
|
||||
.noaltmacro
|
||||
.endm
|
||||
|
||||
# need to push 4 registers into stack to maintain
|
||||
STACK_OFFSET = 8*4
|
||||
|
||||
TMP1 = 16*0 # Temporary storage for AAD
|
||||
TMP2 = 16*1 # Temporary storage for AES State 2 (State 1 is stored in an XMM register)
|
||||
TMP3 = 16*2 # Temporary storage for AES State 3
|
||||
@ -256,25 +249,22 @@ VARIABLE_OFFSET = 16*8
|
||||
################################
|
||||
|
||||
.macro FUNC_SAVE
|
||||
#the number of pushes must equal STACK_OFFSET
|
||||
push %r12
|
||||
push %r13
|
||||
push %r14
|
||||
push %r15
|
||||
|
||||
mov %rsp, %r14
|
||||
|
||||
|
||||
push %rbp
|
||||
mov %rsp, %rbp
|
||||
|
||||
sub $VARIABLE_OFFSET, %rsp
|
||||
and $~63, %rsp # align rsp to 64 bytes
|
||||
.endm
|
||||
|
||||
.macro FUNC_RESTORE
|
||||
mov %r14, %rsp
|
||||
mov %rbp, %rsp
|
||||
pop %rbp
|
||||
|
||||
pop %r15
|
||||
pop %r14
|
||||
pop %r13
|
||||
pop %r12
|
||||
.endm
|
||||
@ -294,7 +284,7 @@ VARIABLE_OFFSET = 16*8
|
||||
|
||||
# combined for GCM encrypt and decrypt functions
|
||||
# clobbering all xmm registers
|
||||
# clobbering r10, r11, r12, r13, r14, r15
|
||||
# clobbering r10, r11, r12, r13, r15, rax
|
||||
.macro GCM_ENC_DEC INITIAL_BLOCKS GHASH_8_ENCRYPT_8_PARALLEL GHASH_LAST_8 GHASH_MUL ENC_DEC REP
|
||||
vmovdqu AadHash(arg2), %xmm8
|
||||
vmovdqu HashKey(arg2), %xmm13 # xmm13 = HashKey
|
||||
@ -996,7 +986,7 @@ _partial_block_done_\@:
|
||||
## num_initial_blocks = b mod 4#
|
||||
## encrypt the initial num_initial_blocks blocks and apply ghash on the ciphertext
|
||||
## r10, r11, r12, rax are clobbered
|
||||
## arg1, arg3, arg4, r14 are used as a pointer only, not modified
|
||||
## arg1, arg2, arg3, arg4 are used as pointers only, not modified
|
||||
|
||||
.macro INITIAL_BLOCKS_AVX REP num_initial_blocks T1 T2 T3 T4 T5 CTR XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 XMM8 T6 T_key ENC_DEC
|
||||
i = (8-\num_initial_blocks)
|
||||
@ -1231,7 +1221,7 @@ _initial_blocks_done\@:
|
||||
|
||||
# encrypt 8 blocks at a time
|
||||
# ghash the 8 previously encrypted ciphertext blocks
|
||||
# arg1, arg3, arg4 are used as pointers only, not modified
|
||||
# arg1, arg2, arg3, arg4 are used as pointers only, not modified
|
||||
# r11 is the data offset value
|
||||
.macro GHASH_8_ENCRYPT_8_PARALLEL_AVX REP T1 T2 T3 T4 T5 T6 CTR XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 XMM8 T7 loop_idx ENC_DEC
|
||||
|
||||
@ -1944,7 +1934,7 @@ SYM_FUNC_END(aesni_gcm_finalize_avx_gen2)
|
||||
## num_initial_blocks = b mod 4#
|
||||
## encrypt the initial num_initial_blocks blocks and apply ghash on the ciphertext
|
||||
## r10, r11, r12, rax are clobbered
|
||||
## arg1, arg3, arg4, r14 are used as a pointer only, not modified
|
||||
## arg1, arg2, arg3, arg4 are used as pointers only, not modified
|
||||
|
||||
.macro INITIAL_BLOCKS_AVX2 REP num_initial_blocks T1 T2 T3 T4 T5 CTR XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 XMM8 T6 T_key ENC_DEC VER
|
||||
i = (8-\num_initial_blocks)
|
||||
@ -2186,7 +2176,7 @@ _initial_blocks_done\@:
|
||||
|
||||
# encrypt 8 blocks at a time
|
||||
# ghash the 8 previously encrypted ciphertext blocks
|
||||
# arg1, arg3, arg4 are used as pointers only, not modified
|
||||
# arg1, arg2, arg3, arg4 are used as pointers only, not modified
|
||||
# r11 is the data offset value
|
||||
.macro GHASH_8_ENCRYPT_8_PARALLEL_AVX2 REP T1 T2 T3 T4 T5 T6 CTR XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 XMM8 T7 loop_idx ENC_DEC
|
||||
|
||||
|
@ -990,6 +990,7 @@ SYM_FUNC_START(camellia_cbc_dec_32way)
|
||||
* %rdx: src (32 blocks)
|
||||
*/
|
||||
FRAME_BEGIN
|
||||
subq $(16 * 32), %rsp;
|
||||
|
||||
vzeroupper;
|
||||
|
||||
@ -1002,7 +1003,6 @@ SYM_FUNC_START(camellia_cbc_dec_32way)
|
||||
%ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14,
|
||||
%ymm15, %rdx, (key_table)(CTX, %r8, 8));
|
||||
|
||||
movq %rsp, %r10;
|
||||
cmpq %rsi, %rdx;
|
||||
je .Lcbc_dec_use_stack;
|
||||
|
||||
@ -1015,7 +1015,6 @@ SYM_FUNC_START(camellia_cbc_dec_32way)
|
||||
* dst still in-use (because dst == src), so use stack for temporary
|
||||
* storage.
|
||||
*/
|
||||
subq $(16 * 32), %rsp;
|
||||
movq %rsp, %rax;
|
||||
|
||||
.Lcbc_dec_continue:
|
||||
@ -1025,7 +1024,6 @@ SYM_FUNC_START(camellia_cbc_dec_32way)
|
||||
vpxor %ymm7, %ymm7, %ymm7;
|
||||
vinserti128 $1, (%rdx), %ymm7, %ymm7;
|
||||
vpxor (%rax), %ymm7, %ymm7;
|
||||
movq %r10, %rsp;
|
||||
vpxor (0 * 32 + 16)(%rdx), %ymm6, %ymm6;
|
||||
vpxor (1 * 32 + 16)(%rdx), %ymm5, %ymm5;
|
||||
vpxor (2 * 32 + 16)(%rdx), %ymm4, %ymm4;
|
||||
@ -1047,6 +1045,7 @@ SYM_FUNC_START(camellia_cbc_dec_32way)
|
||||
|
||||
vzeroupper;
|
||||
|
||||
addq $(16 * 32), %rsp;
|
||||
FRAME_END
|
||||
ret;
|
||||
SYM_FUNC_END(camellia_cbc_dec_32way)
|
||||
|
@ -53,7 +53,7 @@
|
||||
.endm
|
||||
|
||||
.macro JMPTBL_ENTRY i
|
||||
.word crc_\i - crc_array
|
||||
.quad crc_\i
|
||||
.endm
|
||||
|
||||
.macro JNC_LESS_THAN j
|
||||
@ -168,10 +168,7 @@ continue_block:
|
||||
xor crc2, crc2
|
||||
|
||||
## branch into array
|
||||
lea jump_table(%rip), %bufp
|
||||
movzwq (%bufp, %rax, 2), len
|
||||
lea crc_array(%rip), %bufp
|
||||
lea (%bufp, len, 1), %bufp
|
||||
mov jump_table(,%rax,8), %bufp
|
||||
JMP_NOSPEC bufp
|
||||
|
||||
################################################################
|
||||
|
@ -645,9 +645,9 @@ _loop3:
|
||||
RESERVE_STACK = (W_SIZE*4 + 8+24)
|
||||
|
||||
/* Align stack */
|
||||
mov %rsp, %rbx
|
||||
push %rbp
|
||||
mov %rsp, %rbp
|
||||
and $~(0x20-1), %rsp
|
||||
push %rbx
|
||||
sub $RESERVE_STACK, %rsp
|
||||
|
||||
avx2_zeroupper
|
||||
@ -665,8 +665,8 @@ _loop3:
|
||||
|
||||
avx2_zeroupper
|
||||
|
||||
add $RESERVE_STACK, %rsp
|
||||
pop %rsp
|
||||
mov %rbp, %rsp
|
||||
pop %rbp
|
||||
|
||||
pop %r15
|
||||
pop %r14
|
||||
|
@ -59,8 +59,6 @@
|
||||
#define DATA_PTR %rsi /* 2nd arg */
|
||||
#define NUM_BLKS %rdx /* 3rd arg */
|
||||
|
||||
#define RSPSAVE %rax
|
||||
|
||||
/* gcc conversion */
|
||||
#define FRAME_SIZE 32 /* space for 2x16 bytes */
|
||||
|
||||
@ -96,7 +94,8 @@
|
||||
.text
|
||||
.align 32
|
||||
SYM_FUNC_START(sha1_ni_transform)
|
||||
mov %rsp, RSPSAVE
|
||||
push %rbp
|
||||
mov %rsp, %rbp
|
||||
sub $FRAME_SIZE, %rsp
|
||||
and $~0xF, %rsp
|
||||
|
||||
@ -288,7 +287,8 @@ SYM_FUNC_START(sha1_ni_transform)
|
||||
pextrd $3, E0, 1*16(DIGEST_PTR)
|
||||
|
||||
.Ldone_hash:
|
||||
mov RSPSAVE, %rsp
|
||||
mov %rbp, %rsp
|
||||
pop %rbp
|
||||
|
||||
ret
|
||||
SYM_FUNC_END(sha1_ni_transform)
|
||||
|
@ -117,15 +117,13 @@ _XMM_SAVE_SIZE = 0
|
||||
_INP_END_SIZE = 8
|
||||
_INP_SIZE = 8
|
||||
_CTX_SIZE = 8
|
||||
_RSP_SIZE = 8
|
||||
|
||||
_XFER = 0
|
||||
_XMM_SAVE = _XFER + _XFER_SIZE
|
||||
_INP_END = _XMM_SAVE + _XMM_SAVE_SIZE
|
||||
_INP = _INP_END + _INP_END_SIZE
|
||||
_CTX = _INP + _INP_SIZE
|
||||
_RSP = _CTX + _CTX_SIZE
|
||||
STACK_SIZE = _RSP + _RSP_SIZE
|
||||
STACK_SIZE = _CTX + _CTX_SIZE
|
||||
|
||||
# rotate_Xs
|
||||
# Rotate values of symbols X0...X3
|
||||
@ -533,11 +531,11 @@ SYM_FUNC_START(sha256_transform_rorx)
|
||||
pushq %r14
|
||||
pushq %r15
|
||||
|
||||
mov %rsp, %rax
|
||||
push %rbp
|
||||
mov %rsp, %rbp
|
||||
|
||||
subq $STACK_SIZE, %rsp
|
||||
and $-32, %rsp # align rsp to 32 byte boundary
|
||||
mov %rax, _RSP(%rsp)
|
||||
|
||||
|
||||
shl $6, NUM_BLKS # convert to bytes
|
||||
jz done_hash
|
||||
@ -704,7 +702,8 @@ only_one_block:
|
||||
|
||||
done_hash:
|
||||
|
||||
mov _RSP(%rsp), %rsp
|
||||
mov %rbp, %rsp
|
||||
pop %rbp
|
||||
|
||||
popq %r15
|
||||
popq %r14
|
||||
|
@ -76,14 +76,10 @@ tmp0 = %rax
|
||||
W_SIZE = 80*8
|
||||
# W[t] + K[t] | W[t+1] + K[t+1]
|
||||
WK_SIZE = 2*8
|
||||
RSPSAVE_SIZE = 1*8
|
||||
GPRSAVE_SIZE = 5*8
|
||||
|
||||
frame_W = 0
|
||||
frame_WK = frame_W + W_SIZE
|
||||
frame_RSPSAVE = frame_WK + WK_SIZE
|
||||
frame_GPRSAVE = frame_RSPSAVE + RSPSAVE_SIZE
|
||||
frame_size = frame_GPRSAVE + GPRSAVE_SIZE
|
||||
frame_size = frame_WK + WK_SIZE
|
||||
|
||||
# Useful QWORD "arrays" for simpler memory references
|
||||
# MSG, DIGEST, K_t, W_t are arrays
|
||||
@ -281,18 +277,18 @@ SYM_FUNC_START(sha512_transform_avx)
|
||||
test msglen, msglen
|
||||
je nowork
|
||||
|
||||
# Save GPRs
|
||||
push %rbx
|
||||
push %r12
|
||||
push %r13
|
||||
push %r14
|
||||
push %r15
|
||||
|
||||
# Allocate Stack Space
|
||||
mov %rsp, %rax
|
||||
push %rbp
|
||||
mov %rsp, %rbp
|
||||
sub $frame_size, %rsp
|
||||
and $~(0x20 - 1), %rsp
|
||||
mov %rax, frame_RSPSAVE(%rsp)
|
||||
|
||||
# Save GPRs
|
||||
mov %rbx, frame_GPRSAVE(%rsp)
|
||||
mov %r12, frame_GPRSAVE +8*1(%rsp)
|
||||
mov %r13, frame_GPRSAVE +8*2(%rsp)
|
||||
mov %r14, frame_GPRSAVE +8*3(%rsp)
|
||||
mov %r15, frame_GPRSAVE +8*4(%rsp)
|
||||
|
||||
updateblock:
|
||||
|
||||
@ -353,15 +349,16 @@ updateblock:
|
||||
dec msglen
|
||||
jnz updateblock
|
||||
|
||||
# Restore GPRs
|
||||
mov frame_GPRSAVE(%rsp), %rbx
|
||||
mov frame_GPRSAVE +8*1(%rsp), %r12
|
||||
mov frame_GPRSAVE +8*2(%rsp), %r13
|
||||
mov frame_GPRSAVE +8*3(%rsp), %r14
|
||||
mov frame_GPRSAVE +8*4(%rsp), %r15
|
||||
|
||||
# Restore Stack Pointer
|
||||
mov frame_RSPSAVE(%rsp), %rsp
|
||||
mov %rbp, %rsp
|
||||
pop %rbp
|
||||
|
||||
# Restore GPRs
|
||||
pop %r15
|
||||
pop %r14
|
||||
pop %r13
|
||||
pop %r12
|
||||
pop %rbx
|
||||
|
||||
nowork:
|
||||
ret
|
||||
|
@ -102,17 +102,13 @@ SRND_SIZE = 1*8
|
||||
INP_SIZE = 1*8
|
||||
INPEND_SIZE = 1*8
|
||||
CTX_SIZE = 1*8
|
||||
RSPSAVE_SIZE = 1*8
|
||||
GPRSAVE_SIZE = 5*8
|
||||
|
||||
frame_XFER = 0
|
||||
frame_SRND = frame_XFER + XFER_SIZE
|
||||
frame_INP = frame_SRND + SRND_SIZE
|
||||
frame_INPEND = frame_INP + INP_SIZE
|
||||
frame_CTX = frame_INPEND + INPEND_SIZE
|
||||
frame_RSPSAVE = frame_CTX + CTX_SIZE
|
||||
frame_GPRSAVE = frame_RSPSAVE + RSPSAVE_SIZE
|
||||
frame_size = frame_GPRSAVE + GPRSAVE_SIZE
|
||||
frame_size = frame_CTX + CTX_SIZE
|
||||
|
||||
## assume buffers not aligned
|
||||
#define VMOVDQ vmovdqu
|
||||
@ -570,18 +566,18 @@ frame_size = frame_GPRSAVE + GPRSAVE_SIZE
|
||||
# "blocks" is the message length in SHA512 blocks
|
||||
########################################################################
|
||||
SYM_FUNC_START(sha512_transform_rorx)
|
||||
# Save GPRs
|
||||
push %rbx
|
||||
push %r12
|
||||
push %r13
|
||||
push %r14
|
||||
push %r15
|
||||
|
||||
# Allocate Stack Space
|
||||
mov %rsp, %rax
|
||||
push %rbp
|
||||
mov %rsp, %rbp
|
||||
sub $frame_size, %rsp
|
||||
and $~(0x20 - 1), %rsp
|
||||
mov %rax, frame_RSPSAVE(%rsp)
|
||||
|
||||
# Save GPRs
|
||||
mov %rbx, 8*0+frame_GPRSAVE(%rsp)
|
||||
mov %r12, 8*1+frame_GPRSAVE(%rsp)
|
||||
mov %r13, 8*2+frame_GPRSAVE(%rsp)
|
||||
mov %r14, 8*3+frame_GPRSAVE(%rsp)
|
||||
mov %r15, 8*4+frame_GPRSAVE(%rsp)
|
||||
|
||||
shl $7, NUM_BLKS # convert to bytes
|
||||
jz done_hash
|
||||
@ -672,15 +668,17 @@ loop2:
|
||||
|
||||
done_hash:
|
||||
|
||||
# Restore GPRs
|
||||
mov 8*0+frame_GPRSAVE(%rsp), %rbx
|
||||
mov 8*1+frame_GPRSAVE(%rsp), %r12
|
||||
mov 8*2+frame_GPRSAVE(%rsp), %r13
|
||||
mov 8*3+frame_GPRSAVE(%rsp), %r14
|
||||
mov 8*4+frame_GPRSAVE(%rsp), %r15
|
||||
|
||||
# Restore Stack Pointer
|
||||
mov frame_RSPSAVE(%rsp), %rsp
|
||||
mov %rbp, %rsp
|
||||
pop %rbp
|
||||
|
||||
# Restore GPRs
|
||||
pop %r15
|
||||
pop %r14
|
||||
pop %r13
|
||||
pop %r12
|
||||
pop %rbx
|
||||
|
||||
ret
|
||||
SYM_FUNC_END(sha512_transform_rorx)
|
||||
|
||||
|
@ -74,14 +74,10 @@ tmp0 = %rax
|
||||
|
||||
W_SIZE = 80*8
|
||||
WK_SIZE = 2*8
|
||||
RSPSAVE_SIZE = 1*8
|
||||
GPRSAVE_SIZE = 5*8
|
||||
|
||||
frame_W = 0
|
||||
frame_WK = frame_W + W_SIZE
|
||||
frame_RSPSAVE = frame_WK + WK_SIZE
|
||||
frame_GPRSAVE = frame_RSPSAVE + RSPSAVE_SIZE
|
||||
frame_size = frame_GPRSAVE + GPRSAVE_SIZE
|
||||
frame_size = frame_WK + WK_SIZE
|
||||
|
||||
# Useful QWORD "arrays" for simpler memory references
|
||||
# MSG, DIGEST, K_t, W_t are arrays
|
||||
@ -283,18 +279,18 @@ SYM_FUNC_START(sha512_transform_ssse3)
|
||||
test msglen, msglen
|
||||
je nowork
|
||||
|
||||
# Save GPRs
|
||||
push %rbx
|
||||
push %r12
|
||||
push %r13
|
||||
push %r14
|
||||
push %r15
|
||||
|
||||
# Allocate Stack Space
|
||||
mov %rsp, %rax
|
||||
push %rbp
|
||||
mov %rsp, %rbp
|
||||
sub $frame_size, %rsp
|
||||
and $~(0x20 - 1), %rsp
|
||||
mov %rax, frame_RSPSAVE(%rsp)
|
||||
|
||||
# Save GPRs
|
||||
mov %rbx, frame_GPRSAVE(%rsp)
|
||||
mov %r12, frame_GPRSAVE +8*1(%rsp)
|
||||
mov %r13, frame_GPRSAVE +8*2(%rsp)
|
||||
mov %r14, frame_GPRSAVE +8*3(%rsp)
|
||||
mov %r15, frame_GPRSAVE +8*4(%rsp)
|
||||
|
||||
updateblock:
|
||||
|
||||
@ -355,15 +351,16 @@ updateblock:
|
||||
dec msglen
|
||||
jnz updateblock
|
||||
|
||||
# Restore GPRs
|
||||
mov frame_GPRSAVE(%rsp), %rbx
|
||||
mov frame_GPRSAVE +8*1(%rsp), %r12
|
||||
mov frame_GPRSAVE +8*2(%rsp), %r13
|
||||
mov frame_GPRSAVE +8*3(%rsp), %r14
|
||||
mov frame_GPRSAVE +8*4(%rsp), %r15
|
||||
|
||||
# Restore Stack Pointer
|
||||
mov frame_RSPSAVE(%rsp), %rsp
|
||||
mov %rbp, %rsp
|
||||
pop %rbp
|
||||
|
||||
# Restore GPRs
|
||||
pop %r15
|
||||
pop %r14
|
||||
pop %r13
|
||||
pop %r12
|
||||
pop %rbx
|
||||
|
||||
nowork:
|
||||
ret
|
||||
|
@ -21,17 +21,6 @@
|
||||
#include <objtool/warn.h>
|
||||
#include <arch/elf.h>
|
||||
|
||||
static unsigned char op_to_cfi_reg[][2] = {
|
||||
{CFI_AX, CFI_R8},
|
||||
{CFI_CX, CFI_R9},
|
||||
{CFI_DX, CFI_R10},
|
||||
{CFI_BX, CFI_R11},
|
||||
{CFI_SP, CFI_R12},
|
||||
{CFI_BP, CFI_R13},
|
||||
{CFI_SI, CFI_R14},
|
||||
{CFI_DI, CFI_R15},
|
||||
};
|
||||
|
||||
static int is_x86_64(const struct elf *elf)
|
||||
{
|
||||
switch (elf->ehdr.e_machine) {
|
||||
@ -87,6 +76,31 @@ unsigned long arch_jump_destination(struct instruction *insn)
|
||||
return -1; \
|
||||
else for (list_add_tail(&op->list, ops_list); op; op = NULL)
|
||||
|
||||
/*
|
||||
* Helpers to decode ModRM/SIB:
|
||||
*
|
||||
* r/m| AX CX DX BX | SP | BP | SI DI |
|
||||
* | R8 R9 R10 R11 | R12 | R13 | R14 R15 |
|
||||
* Mod+----------------+-----+-----+---------+
|
||||
* 00 | [r/m] |[SIB]|[IP+]| [r/m] |
|
||||
* 01 | [r/m + d8] |[S+d]| [r/m + d8] |
|
||||
* 10 | [r/m + d32] |[S+D]| [r/m + d32] |
|
||||
* 11 | r/ m |
|
||||
*/
|
||||
|
||||
#define mod_is_mem() (modrm_mod != 3)
|
||||
#define mod_is_reg() (modrm_mod == 3)
|
||||
|
||||
#define is_RIP() ((modrm_rm & 7) == CFI_BP && modrm_mod == 0)
|
||||
#define have_SIB() ((modrm_rm & 7) == CFI_SP && mod_is_mem())
|
||||
|
||||
#define rm_is(reg) (have_SIB() ? \
|
||||
sib_base == (reg) && sib_index == CFI_SP : \
|
||||
modrm_rm == (reg))
|
||||
|
||||
#define rm_is_mem(reg) (mod_is_mem() && !is_RIP() && rm_is(reg))
|
||||
#define rm_is_reg(reg) (mod_is_reg() && modrm_rm == (reg))
|
||||
|
||||
int arch_decode_instruction(const struct elf *elf, const struct section *sec,
|
||||
unsigned long offset, unsigned int maxlen,
|
||||
unsigned int *len, enum insn_type *type,
|
||||
@ -94,12 +108,14 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec,
|
||||
struct list_head *ops_list)
|
||||
{
|
||||
struct insn insn;
|
||||
int x86_64, sign, ret;
|
||||
unsigned char op1, op2, rex = 0, rex_b = 0, rex_r = 0, rex_w = 0,
|
||||
rex_x = 0, modrm = 0, modrm_mod = 0, modrm_rm = 0,
|
||||
modrm_reg = 0, sib = 0;
|
||||
int x86_64, ret;
|
||||
unsigned char op1, op2,
|
||||
rex = 0, rex_b = 0, rex_r = 0, rex_w = 0, rex_x = 0,
|
||||
modrm = 0, modrm_mod = 0, modrm_rm = 0, modrm_reg = 0,
|
||||
sib = 0, /* sib_scale = 0, */ sib_index = 0, sib_base = 0;
|
||||
struct stack_op *op = NULL;
|
||||
struct symbol *sym;
|
||||
u64 imm;
|
||||
|
||||
x86_64 = is_x86_64(elf);
|
||||
if (x86_64 == -1)
|
||||
@ -132,23 +148,27 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec,
|
||||
if (insn.modrm.nbytes) {
|
||||
modrm = insn.modrm.bytes[0];
|
||||
modrm_mod = X86_MODRM_MOD(modrm);
|
||||
modrm_reg = X86_MODRM_REG(modrm);
|
||||
modrm_rm = X86_MODRM_RM(modrm);
|
||||
modrm_reg = X86_MODRM_REG(modrm) + 8*rex_r;
|
||||
modrm_rm = X86_MODRM_RM(modrm) + 8*rex_b;
|
||||
}
|
||||
|
||||
if (insn.sib.nbytes)
|
||||
if (insn.sib.nbytes) {
|
||||
sib = insn.sib.bytes[0];
|
||||
/* sib_scale = X86_SIB_SCALE(sib); */
|
||||
sib_index = X86_SIB_INDEX(sib) + 8*rex_x;
|
||||
sib_base = X86_SIB_BASE(sib) + 8*rex_b;
|
||||
}
|
||||
|
||||
switch (op1) {
|
||||
|
||||
case 0x1:
|
||||
case 0x29:
|
||||
if (rex_w && !rex_b && modrm_mod == 3 && modrm_rm == 4) {
|
||||
if (rex_w && rm_is_reg(CFI_SP)) {
|
||||
|
||||
/* add/sub reg, %rsp */
|
||||
ADD_OP(op) {
|
||||
op->src.type = OP_SRC_ADD;
|
||||
op->src.reg = op_to_cfi_reg[modrm_reg][rex_r];
|
||||
op->src.reg = modrm_reg;
|
||||
op->dest.type = OP_DEST_REG;
|
||||
op->dest.reg = CFI_SP;
|
||||
}
|
||||
@ -160,7 +180,7 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec,
|
||||
/* push reg */
|
||||
ADD_OP(op) {
|
||||
op->src.type = OP_SRC_REG;
|
||||
op->src.reg = op_to_cfi_reg[op1 & 0x7][rex_b];
|
||||
op->src.reg = (op1 & 0x7) + 8*rex_b;
|
||||
op->dest.type = OP_DEST_PUSH;
|
||||
}
|
||||
|
||||
@ -172,7 +192,7 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec,
|
||||
ADD_OP(op) {
|
||||
op->src.type = OP_SRC_POP;
|
||||
op->dest.type = OP_DEST_REG;
|
||||
op->dest.reg = op_to_cfi_reg[op1 & 0x7][rex_b];
|
||||
op->dest.reg = (op1 & 0x7) + 8*rex_b;
|
||||
}
|
||||
|
||||
break;
|
||||
@ -190,12 +210,54 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec,
|
||||
*type = INSN_JUMP_CONDITIONAL;
|
||||
break;
|
||||
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
if (rex != 0x48)
|
||||
case 0x80 ... 0x83:
|
||||
/*
|
||||
* 1000 00sw : mod OP r/m : immediate
|
||||
*
|
||||
* s - sign extend immediate
|
||||
* w - imm8 / imm32
|
||||
*
|
||||
* OP: 000 ADD 100 AND
|
||||
* 001 OR 101 SUB
|
||||
* 010 ADC 110 XOR
|
||||
* 011 SBB 111 CMP
|
||||
*/
|
||||
|
||||
/* 64bit only */
|
||||
if (!rex_w)
|
||||
break;
|
||||
|
||||
if (modrm == 0xe4) {
|
||||
/* %rsp target only */
|
||||
if (!rm_is_reg(CFI_SP))
|
||||
break;
|
||||
|
||||
imm = insn.immediate.value;
|
||||
if (op1 & 2) { /* sign extend */
|
||||
if (op1 & 1) { /* imm32 */
|
||||
imm <<= 32;
|
||||
imm = (s64)imm >> 32;
|
||||
} else { /* imm8 */
|
||||
imm <<= 56;
|
||||
imm = (s64)imm >> 56;
|
||||
}
|
||||
}
|
||||
|
||||
switch (modrm_reg & 7) {
|
||||
case 5:
|
||||
imm = -imm;
|
||||
/* fallthrough */
|
||||
case 0:
|
||||
/* add/sub imm, %rsp */
|
||||
ADD_OP(op) {
|
||||
op->src.type = OP_SRC_ADD;
|
||||
op->src.reg = CFI_SP;
|
||||
op->src.offset = imm;
|
||||
op->dest.type = OP_DEST_REG;
|
||||
op->dest.reg = CFI_SP;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
/* and imm, %rsp */
|
||||
ADD_OP(op) {
|
||||
op->src.type = OP_SRC_AND;
|
||||
@ -205,53 +267,48 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec,
|
||||
op->dest.reg = CFI_SP;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (modrm == 0xc4)
|
||||
sign = 1;
|
||||
else if (modrm == 0xec)
|
||||
sign = -1;
|
||||
else
|
||||
default:
|
||||
/* WARN ? */
|
||||
break;
|
||||
|
||||
/* add/sub imm, %rsp */
|
||||
ADD_OP(op) {
|
||||
op->src.type = OP_SRC_ADD;
|
||||
op->src.reg = CFI_SP;
|
||||
op->src.offset = insn.immediate.value * sign;
|
||||
op->dest.type = OP_DEST_REG;
|
||||
op->dest.reg = CFI_SP;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 0x89:
|
||||
if (rex_w && !rex_r && modrm_reg == 4) {
|
||||
if (!rex_w)
|
||||
break;
|
||||
|
||||
if (modrm_mod == 3) {
|
||||
if (modrm_reg == CFI_SP) {
|
||||
|
||||
if (mod_is_reg()) {
|
||||
/* mov %rsp, reg */
|
||||
ADD_OP(op) {
|
||||
op->src.type = OP_SRC_REG;
|
||||
op->src.reg = CFI_SP;
|
||||
op->dest.type = OP_DEST_REG;
|
||||
op->dest.reg = op_to_cfi_reg[modrm_rm][rex_b];
|
||||
op->dest.reg = modrm_rm;
|
||||
}
|
||||
break;
|
||||
|
||||
} else {
|
||||
/* skip nontrivial SIB */
|
||||
if (modrm_rm == 4 && !(sib == 0x24 && rex_b == rex_x))
|
||||
/* skip RIP relative displacement */
|
||||
if (is_RIP())
|
||||
break;
|
||||
|
||||
/* skip RIP relative displacement */
|
||||
if (modrm_rm == 5 && modrm_mod == 0)
|
||||
break;
|
||||
/* skip nontrivial SIB */
|
||||
if (have_SIB()) {
|
||||
modrm_rm = sib_base;
|
||||
if (sib_index != CFI_SP)
|
||||
break;
|
||||
}
|
||||
|
||||
/* mov %rsp, disp(%reg) */
|
||||
ADD_OP(op) {
|
||||
op->src.type = OP_SRC_REG;
|
||||
op->src.reg = CFI_SP;
|
||||
op->dest.type = OP_DEST_REG_INDIRECT;
|
||||
op->dest.reg = op_to_cfi_reg[modrm_rm][rex_b];
|
||||
op->dest.reg = modrm_rm;
|
||||
op->dest.offset = insn.displacement.value;
|
||||
}
|
||||
break;
|
||||
@ -260,12 +317,12 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec,
|
||||
break;
|
||||
}
|
||||
|
||||
if (rex_w && !rex_b && modrm_mod == 3 && modrm_rm == 4) {
|
||||
if (rm_is_reg(CFI_SP)) {
|
||||
|
||||
/* mov reg, %rsp */
|
||||
ADD_OP(op) {
|
||||
op->src.type = OP_SRC_REG;
|
||||
op->src.reg = op_to_cfi_reg[modrm_reg][rex_r];
|
||||
op->src.reg = modrm_reg;
|
||||
op->dest.type = OP_DEST_REG;
|
||||
op->dest.reg = CFI_SP;
|
||||
}
|
||||
@ -274,13 +331,15 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec,
|
||||
|
||||
/* fallthrough */
|
||||
case 0x88:
|
||||
if (!rex_b &&
|
||||
(modrm_mod == 1 || modrm_mod == 2) && modrm_rm == 5) {
|
||||
if (!rex_w)
|
||||
break;
|
||||
|
||||
if (rm_is_mem(CFI_BP)) {
|
||||
|
||||
/* mov reg, disp(%rbp) */
|
||||
ADD_OP(op) {
|
||||
op->src.type = OP_SRC_REG;
|
||||
op->src.reg = op_to_cfi_reg[modrm_reg][rex_r];
|
||||
op->src.reg = modrm_reg;
|
||||
op->dest.type = OP_DEST_REG_INDIRECT;
|
||||
op->dest.reg = CFI_BP;
|
||||
op->dest.offset = insn.displacement.value;
|
||||
@ -288,12 +347,12 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec,
|
||||
break;
|
||||
}
|
||||
|
||||
if (rex_w && !rex_b && modrm_rm == 4 && sib == 0x24) {
|
||||
if (rm_is_mem(CFI_SP)) {
|
||||
|
||||
/* mov reg, disp(%rsp) */
|
||||
ADD_OP(op) {
|
||||
op->src.type = OP_SRC_REG;
|
||||
op->src.reg = op_to_cfi_reg[modrm_reg][rex_r];
|
||||
op->src.reg = modrm_reg;
|
||||
op->dest.type = OP_DEST_REG_INDIRECT;
|
||||
op->dest.reg = CFI_SP;
|
||||
op->dest.offset = insn.displacement.value;
|
||||
@ -304,7 +363,10 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec,
|
||||
break;
|
||||
|
||||
case 0x8b:
|
||||
if (rex_w && !rex_b && modrm_mod == 1 && modrm_rm == 5) {
|
||||
if (!rex_w)
|
||||
break;
|
||||
|
||||
if (rm_is_mem(CFI_BP)) {
|
||||
|
||||
/* mov disp(%rbp), reg */
|
||||
ADD_OP(op) {
|
||||
@ -312,11 +374,12 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec,
|
||||
op->src.reg = CFI_BP;
|
||||
op->src.offset = insn.displacement.value;
|
||||
op->dest.type = OP_DEST_REG;
|
||||
op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r];
|
||||
op->dest.reg = modrm_reg;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (rex_w && !rex_b && sib == 0x24 &&
|
||||
modrm_mod != 3 && modrm_rm == 4) {
|
||||
if (rm_is_mem(CFI_SP)) {
|
||||
|
||||
/* mov disp(%rsp), reg */
|
||||
ADD_OP(op) {
|
||||
@ -324,75 +387,48 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec,
|
||||
op->src.reg = CFI_SP;
|
||||
op->src.offset = insn.displacement.value;
|
||||
op->dest.type = OP_DEST_REG;
|
||||
op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r];
|
||||
op->dest.reg = modrm_reg;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 0x8d:
|
||||
if (sib == 0x24 && rex_w && !rex_b && !rex_x) {
|
||||
|
||||
ADD_OP(op) {
|
||||
if (!insn.displacement.value) {
|
||||
/* lea (%rsp), reg */
|
||||
op->src.type = OP_SRC_REG;
|
||||
} else {
|
||||
/* lea disp(%rsp), reg */
|
||||
op->src.type = OP_SRC_ADD;
|
||||
op->src.offset = insn.displacement.value;
|
||||
}
|
||||
op->src.reg = CFI_SP;
|
||||
op->dest.type = OP_DEST_REG;
|
||||
op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r];
|
||||
}
|
||||
|
||||
} else if (rex == 0x48 && modrm == 0x65) {
|
||||
|
||||
/* lea disp(%rbp), %rsp */
|
||||
ADD_OP(op) {
|
||||
op->src.type = OP_SRC_ADD;
|
||||
op->src.reg = CFI_BP;
|
||||
op->src.offset = insn.displacement.value;
|
||||
op->dest.type = OP_DEST_REG;
|
||||
op->dest.reg = CFI_SP;
|
||||
}
|
||||
|
||||
} else if (rex == 0x49 && modrm == 0x62 &&
|
||||
insn.displacement.value == -8) {
|
||||
|
||||
/*
|
||||
* lea -0x8(%r10), %rsp
|
||||
*
|
||||
* Restoring rsp back to its original value after a
|
||||
* stack realignment.
|
||||
*/
|
||||
ADD_OP(op) {
|
||||
op->src.type = OP_SRC_ADD;
|
||||
op->src.reg = CFI_R10;
|
||||
op->src.offset = -8;
|
||||
op->dest.type = OP_DEST_REG;
|
||||
op->dest.reg = CFI_SP;
|
||||
}
|
||||
|
||||
} else if (rex == 0x49 && modrm == 0x65 &&
|
||||
insn.displacement.value == -16) {
|
||||
|
||||
/*
|
||||
* lea -0x10(%r13), %rsp
|
||||
*
|
||||
* Restoring rsp back to its original value after a
|
||||
* stack realignment.
|
||||
*/
|
||||
ADD_OP(op) {
|
||||
op->src.type = OP_SRC_ADD;
|
||||
op->src.reg = CFI_R13;
|
||||
op->src.offset = -16;
|
||||
op->dest.type = OP_DEST_REG;
|
||||
op->dest.reg = CFI_SP;
|
||||
}
|
||||
if (mod_is_reg()) {
|
||||
WARN("invalid LEA encoding at %s:0x%lx", sec->name, offset);
|
||||
break;
|
||||
}
|
||||
|
||||
/* skip non 64bit ops */
|
||||
if (!rex_w)
|
||||
break;
|
||||
|
||||
/* skip RIP relative displacement */
|
||||
if (is_RIP())
|
||||
break;
|
||||
|
||||
/* skip nontrivial SIB */
|
||||
if (have_SIB()) {
|
||||
modrm_rm = sib_base;
|
||||
if (sib_index != CFI_SP)
|
||||
break;
|
||||
}
|
||||
|
||||
/* lea disp(%src), %dst */
|
||||
ADD_OP(op) {
|
||||
op->src.offset = insn.displacement.value;
|
||||
if (!op->src.offset) {
|
||||
/* lea (%src), %dst */
|
||||
op->src.type = OP_SRC_REG;
|
||||
} else {
|
||||
/* lea disp(%src), %dst */
|
||||
op->src.type = OP_SRC_ADD;
|
||||
}
|
||||
op->src.reg = modrm_rm;
|
||||
op->dest.type = OP_DEST_REG;
|
||||
op->dest.reg = modrm_reg;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8f:
|
||||
@ -479,9 +515,17 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec,
|
||||
* mov bp, sp
|
||||
* pop bp
|
||||
*/
|
||||
ADD_OP(op)
|
||||
op->dest.type = OP_DEST_LEAVE;
|
||||
|
||||
ADD_OP(op) {
|
||||
op->src.type = OP_SRC_REG;
|
||||
op->src.reg = CFI_BP;
|
||||
op->dest.type = OP_DEST_REG;
|
||||
op->dest.reg = CFI_SP;
|
||||
}
|
||||
ADD_OP(op) {
|
||||
op->src.type = OP_SRC_POP;
|
||||
op->dest.type = OP_DEST_REG;
|
||||
op->dest.reg = CFI_BP;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xe3:
|
||||
|
@ -4,13 +4,13 @@
|
||||
#define _OBJTOOL_CFI_REGS_H
|
||||
|
||||
#define CFI_AX 0
|
||||
#define CFI_DX 1
|
||||
#define CFI_CX 2
|
||||
#define CFI_CX 1
|
||||
#define CFI_DX 2
|
||||
#define CFI_BX 3
|
||||
#define CFI_SI 4
|
||||
#define CFI_DI 5
|
||||
#define CFI_BP 6
|
||||
#define CFI_SP 7
|
||||
#define CFI_SP 4
|
||||
#define CFI_BP 5
|
||||
#define CFI_SI 6
|
||||
#define CFI_DI 7
|
||||
#define CFI_R8 8
|
||||
#define CFI_R9 9
|
||||
#define CFI_R10 10
|
||||
|
@ -15,16 +15,23 @@
|
||||
|
||||
#include <subcmd/parse-options.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <objtool/builtin.h>
|
||||
#include <objtool/objtool.h>
|
||||
|
||||
bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess, stats, validate_dup, vmlinux, mcount, noinstr;
|
||||
bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess, stats,
|
||||
validate_dup, vmlinux, mcount, noinstr, backup;
|
||||
|
||||
static const char * const check_usage[] = {
|
||||
"objtool check [<options>] file.o",
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const char * const env_usage[] = {
|
||||
"OBJTOOL_ARGS=\"<options>\"",
|
||||
NULL,
|
||||
};
|
||||
|
||||
const struct option check_options[] = {
|
||||
OPT_BOOLEAN('f', "no-fp", &no_fp, "Skip frame pointer validation"),
|
||||
OPT_BOOLEAN('u', "no-unreachable", &no_unreachable, "Skip 'unreachable instruction' warnings"),
|
||||
@ -37,20 +44,44 @@ const struct option check_options[] = {
|
||||
OPT_BOOLEAN('n', "noinstr", &noinstr, "noinstr validation for vmlinux.o"),
|
||||
OPT_BOOLEAN('l', "vmlinux", &vmlinux, "vmlinux.o validation"),
|
||||
OPT_BOOLEAN('M', "mcount", &mcount, "generate __mcount_loc"),
|
||||
OPT_BOOLEAN('B', "backup", &backup, "create .orig files before modification"),
|
||||
OPT_END(),
|
||||
};
|
||||
|
||||
int cmd_parse_options(int argc, const char **argv, const char * const usage[])
|
||||
{
|
||||
const char *envv[16] = { };
|
||||
char *env;
|
||||
int envc;
|
||||
|
||||
env = getenv("OBJTOOL_ARGS");
|
||||
if (env) {
|
||||
envv[0] = "OBJTOOL_ARGS";
|
||||
for (envc = 1; envc < ARRAY_SIZE(envv); ) {
|
||||
envv[envc++] = env;
|
||||
env = strchr(env, ' ');
|
||||
if (!env)
|
||||
break;
|
||||
*env = '\0';
|
||||
env++;
|
||||
}
|
||||
|
||||
parse_options(envc, envv, check_options, env_usage, 0);
|
||||
}
|
||||
|
||||
argc = parse_options(argc, argv, check_options, usage, 0);
|
||||
if (argc != 1)
|
||||
usage_with_options(usage, check_options);
|
||||
return argc;
|
||||
}
|
||||
|
||||
int cmd_check(int argc, const char **argv)
|
||||
{
|
||||
const char *objname;
|
||||
struct objtool_file *file;
|
||||
int ret;
|
||||
|
||||
argc = parse_options(argc, argv, check_options, check_usage, 0);
|
||||
|
||||
if (argc != 1)
|
||||
usage_with_options(check_usage, check_options);
|
||||
|
||||
argc = cmd_parse_options(argc, argv, check_usage);
|
||||
objname = argv[0];
|
||||
|
||||
file = objtool_open_read(objname);
|
||||
|
@ -34,10 +34,7 @@ int cmd_orc(int argc, const char **argv)
|
||||
struct objtool_file *file;
|
||||
int ret;
|
||||
|
||||
argc = parse_options(argc, argv, check_options, orc_usage, 0);
|
||||
if (argc != 1)
|
||||
usage_with_options(orc_usage, check_options);
|
||||
|
||||
argc = cmd_parse_options(argc, argv, orc_usage);
|
||||
objname = argv[0];
|
||||
|
||||
file = objtool_open_read(objname);
|
||||
|
@ -108,6 +108,18 @@ static struct instruction *prev_insn_same_sym(struct objtool_file *file,
|
||||
for (insn = next_insn_same_sec(file, insn); insn; \
|
||||
insn = next_insn_same_sec(file, insn))
|
||||
|
||||
static bool is_jump_table_jump(struct instruction *insn)
|
||||
{
|
||||
struct alt_group *alt_group = insn->alt_group;
|
||||
|
||||
if (insn->jump_table)
|
||||
return true;
|
||||
|
||||
/* Retpoline alternative for a jump table? */
|
||||
return alt_group && alt_group->orig_group &&
|
||||
alt_group->orig_group->first_insn->jump_table;
|
||||
}
|
||||
|
||||
static bool is_sibling_call(struct instruction *insn)
|
||||
{
|
||||
/*
|
||||
@ -120,7 +132,7 @@ static bool is_sibling_call(struct instruction *insn)
|
||||
|
||||
/* An indirect jump is either a sibling call or a jump to a table. */
|
||||
if (insn->type == INSN_JUMP_DYNAMIC)
|
||||
return list_empty(&insn->alts);
|
||||
return !is_jump_table_jump(insn);
|
||||
|
||||
/* add_jump_destinations() sets insn->call_dest for sibling calls. */
|
||||
return (is_static_jump(insn) && insn->call_dest);
|
||||
@ -1969,8 +1981,9 @@ static void restore_reg(struct cfi_state *cfi, unsigned char reg)
|
||||
* 41 5d pop %r13
|
||||
* c3 retq
|
||||
*/
|
||||
static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi,
|
||||
struct stack_op *op)
|
||||
static int update_cfi_state(struct instruction *insn,
|
||||
struct instruction *next_insn,
|
||||
struct cfi_state *cfi, struct stack_op *op)
|
||||
{
|
||||
struct cfi_reg *cfa = &cfi->cfa;
|
||||
struct cfi_reg *regs = cfi->regs;
|
||||
@ -2029,7 +2042,7 @@ static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi,
|
||||
}
|
||||
|
||||
else if (op->src.reg == CFI_BP && op->dest.reg == CFI_SP &&
|
||||
cfa->base == CFI_BP) {
|
||||
(cfa->base == CFI_BP || cfa->base == cfi->drap_reg)) {
|
||||
|
||||
/*
|
||||
* mov %rbp, %rsp
|
||||
@ -2171,7 +2184,7 @@ static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi,
|
||||
break;
|
||||
}
|
||||
|
||||
if (op->dest.reg == cfi->cfa.base) {
|
||||
if (op->dest.reg == cfi->cfa.base && !(next_insn && next_insn->hint)) {
|
||||
WARN_FUNC("unsupported stack register modification",
|
||||
insn->sec, insn->offset);
|
||||
return -1;
|
||||
@ -2226,7 +2239,7 @@ static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi,
|
||||
cfa->offset = 0;
|
||||
cfi->drap_offset = -1;
|
||||
|
||||
} else if (regs[op->dest.reg].offset == -cfi->stack_size) {
|
||||
} else if (cfi->stack_size == -regs[op->dest.reg].offset) {
|
||||
|
||||
/* pop %reg */
|
||||
restore_reg(cfi, op->dest.reg);
|
||||
@ -2367,26 +2380,6 @@ static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi,
|
||||
|
||||
break;
|
||||
|
||||
case OP_DEST_LEAVE:
|
||||
if ((!cfi->drap && cfa->base != CFI_BP) ||
|
||||
(cfi->drap && cfa->base != cfi->drap_reg)) {
|
||||
WARN_FUNC("leave instruction with modified stack frame",
|
||||
insn->sec, insn->offset);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* leave (mov %rbp, %rsp; pop %rbp) */
|
||||
|
||||
cfi->stack_size = -cfi->regs[CFI_BP].offset - 8;
|
||||
restore_reg(cfi, CFI_BP);
|
||||
|
||||
if (!cfi->drap) {
|
||||
cfa->base = CFI_SP;
|
||||
cfa->offset -= 8;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case OP_DEST_MEM:
|
||||
if (op->src.type != OP_SRC_POP && op->src.type != OP_SRC_POPF) {
|
||||
WARN_FUNC("unknown stack-related memory operation",
|
||||
@ -2443,13 +2436,15 @@ static int propagate_alt_cfi(struct objtool_file *file, struct instruction *insn
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_insn_ops(struct instruction *insn, struct insn_state *state)
|
||||
static int handle_insn_ops(struct instruction *insn,
|
||||
struct instruction *next_insn,
|
||||
struct insn_state *state)
|
||||
{
|
||||
struct stack_op *op;
|
||||
|
||||
list_for_each_entry(op, &insn->stack_ops, list) {
|
||||
|
||||
if (update_cfi_state(insn, &state->cfi, op))
|
||||
if (update_cfi_state(insn, next_insn, &state->cfi, op))
|
||||
return 1;
|
||||
|
||||
if (!insn->alt_group)
|
||||
@ -2732,7 +2727,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (handle_insn_ops(insn, &state))
|
||||
if (handle_insn_ops(insn, next_insn, &state))
|
||||
return 1;
|
||||
|
||||
switch (insn->type) {
|
||||
|
@ -35,7 +35,6 @@ enum op_dest_type {
|
||||
OP_DEST_MEM,
|
||||
OP_DEST_PUSH,
|
||||
OP_DEST_PUSHF,
|
||||
OP_DEST_LEAVE,
|
||||
};
|
||||
|
||||
struct op_dest {
|
||||
|
@ -8,7 +8,10 @@
|
||||
#include <subcmd/parse-options.h>
|
||||
|
||||
extern const struct option check_options[];
|
||||
extern bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess, stats, validate_dup, vmlinux, mcount, noinstr;
|
||||
extern bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess, stats,
|
||||
validate_dup, vmlinux, mcount, noinstr, backup;
|
||||
|
||||
extern int cmd_parse_options(int argc, const char **argv, const char * const usage[]);
|
||||
|
||||
extern int cmd_check(int argc, const char **argv);
|
||||
extern int cmd_orc(int argc, const char **argv);
|
||||
|
@ -17,6 +17,7 @@
|
||||
#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>
|
||||
@ -44,6 +45,64 @@ 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) {
|
||||
@ -59,6 +118,11 @@ struct objtool_file *objtool_open_read(const char *_objname)
|
||||
if (!file.elf)
|
||||
return NULL;
|
||||
|
||||
if (backup && !objtool_create_backup(objname)) {
|
||||
WARN("can't create backup file");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&file.insn_list);
|
||||
hash_init(file.insn_hash);
|
||||
INIT_LIST_HEAD(&file.retpoline_call_list);
|
||||
|
Loading…
x
Reference in New Issue
Block a user