Commit 03b2cd72 authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents 0ff0edb5 7d3d10e0
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
# #
# x86 crypto algorithms # x86 crypto algorithms
OBJECT_FILES_NON_STANDARD := y
obj-$(CONFIG_CRYPTO_TWOFISH_586) += twofish-i586.o obj-$(CONFIG_CRYPTO_TWOFISH_586) += twofish-i586.o
twofish-i586-y := twofish-i586-asm_32.o twofish_glue.o twofish-i586-y := twofish-i586-asm_32.o twofish_glue.o
obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.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 ...@@ -212,10 +212,6 @@ HashKey_8_k = 16*21 # store XOR of HashKey^8 <<1 mod poly here (for Karatsu
#define arg4 %rcx #define arg4 %rcx
#define arg5 %r8 #define arg5 %r8
#define arg6 %r9 #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) #define keysize 2*15*16(arg1)
i = 0 i = 0
...@@ -237,9 +233,6 @@ define_reg j %j ...@@ -237,9 +233,6 @@ define_reg j %j
.noaltmacro .noaltmacro
.endm .endm
# need to push 4 registers into stack to maintain
STACK_OFFSET = 8*4
TMP1 = 16*0 # Temporary storage for AAD TMP1 = 16*0 # Temporary storage for AAD
TMP2 = 16*1 # Temporary storage for AES State 2 (State 1 is stored in an XMM register) 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 TMP3 = 16*2 # Temporary storage for AES State 3
...@@ -256,25 +249,22 @@ VARIABLE_OFFSET = 16*8 ...@@ -256,25 +249,22 @@ VARIABLE_OFFSET = 16*8
################################ ################################
.macro FUNC_SAVE .macro FUNC_SAVE
#the number of pushes must equal STACK_OFFSET
push %r12 push %r12
push %r13 push %r13
push %r14
push %r15 push %r15
mov %rsp, %r14 push %rbp
mov %rsp, %rbp
sub $VARIABLE_OFFSET, %rsp sub $VARIABLE_OFFSET, %rsp
and $~63, %rsp # align rsp to 64 bytes and $~63, %rsp # align rsp to 64 bytes
.endm .endm
.macro FUNC_RESTORE .macro FUNC_RESTORE
mov %r14, %rsp mov %rbp, %rsp
pop %rbp
pop %r15 pop %r15
pop %r14
pop %r13 pop %r13
pop %r12 pop %r12
.endm .endm
...@@ -294,7 +284,7 @@ VARIABLE_OFFSET = 16*8 ...@@ -294,7 +284,7 @@ VARIABLE_OFFSET = 16*8
# combined for GCM encrypt and decrypt functions # combined for GCM encrypt and decrypt functions
# clobbering all xmm registers # 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 .macro GCM_ENC_DEC INITIAL_BLOCKS GHASH_8_ENCRYPT_8_PARALLEL GHASH_LAST_8 GHASH_MUL ENC_DEC REP
vmovdqu AadHash(arg2), %xmm8 vmovdqu AadHash(arg2), %xmm8
vmovdqu HashKey(arg2), %xmm13 # xmm13 = HashKey vmovdqu HashKey(arg2), %xmm13 # xmm13 = HashKey
...@@ -996,7 +986,7 @@ _partial_block_done_\@: ...@@ -996,7 +986,7 @@ _partial_block_done_\@:
## num_initial_blocks = b mod 4# ## num_initial_blocks = b mod 4#
## encrypt the initial num_initial_blocks blocks and apply ghash on the ciphertext ## encrypt the initial num_initial_blocks blocks and apply ghash on the ciphertext
## r10, r11, r12, rax are clobbered ## 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 .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) i = (8-\num_initial_blocks)
...@@ -1231,7 +1221,7 @@ _initial_blocks_done\@: ...@@ -1231,7 +1221,7 @@ _initial_blocks_done\@:
# encrypt 8 blocks at a time # encrypt 8 blocks at a time
# ghash the 8 previously encrypted ciphertext blocks # 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 # 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 .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) ...@@ -1944,7 +1934,7 @@ SYM_FUNC_END(aesni_gcm_finalize_avx_gen2)
## num_initial_blocks = b mod 4# ## num_initial_blocks = b mod 4#
## encrypt the initial num_initial_blocks blocks and apply ghash on the ciphertext ## encrypt the initial num_initial_blocks blocks and apply ghash on the ciphertext
## r10, r11, r12, rax are clobbered ## 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 .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) i = (8-\num_initial_blocks)
...@@ -2186,7 +2176,7 @@ _initial_blocks_done\@: ...@@ -2186,7 +2176,7 @@ _initial_blocks_done\@:
# encrypt 8 blocks at a time # encrypt 8 blocks at a time
# ghash the 8 previously encrypted ciphertext blocks # 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 # 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 .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) ...@@ -990,6 +990,7 @@ SYM_FUNC_START(camellia_cbc_dec_32way)
* %rdx: src (32 blocks) * %rdx: src (32 blocks)
*/ */
FRAME_BEGIN FRAME_BEGIN
subq $(16 * 32), %rsp;
vzeroupper; vzeroupper;
...@@ -1002,7 +1003,6 @@ SYM_FUNC_START(camellia_cbc_dec_32way) ...@@ -1002,7 +1003,6 @@ SYM_FUNC_START(camellia_cbc_dec_32way)
%ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14, %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14,
%ymm15, %rdx, (key_table)(CTX, %r8, 8)); %ymm15, %rdx, (key_table)(CTX, %r8, 8));
movq %rsp, %r10;
cmpq %rsi, %rdx; cmpq %rsi, %rdx;
je .Lcbc_dec_use_stack; je .Lcbc_dec_use_stack;
...@@ -1015,7 +1015,6 @@ SYM_FUNC_START(camellia_cbc_dec_32way) ...@@ -1015,7 +1015,6 @@ SYM_FUNC_START(camellia_cbc_dec_32way)
* dst still in-use (because dst == src), so use stack for temporary * dst still in-use (because dst == src), so use stack for temporary
* storage. * storage.
*/ */
subq $(16 * 32), %rsp;
movq %rsp, %rax; movq %rsp, %rax;
.Lcbc_dec_continue: .Lcbc_dec_continue:
...@@ -1025,7 +1024,6 @@ SYM_FUNC_START(camellia_cbc_dec_32way) ...@@ -1025,7 +1024,6 @@ SYM_FUNC_START(camellia_cbc_dec_32way)
vpxor %ymm7, %ymm7, %ymm7; vpxor %ymm7, %ymm7, %ymm7;
vinserti128 $1, (%rdx), %ymm7, %ymm7; vinserti128 $1, (%rdx), %ymm7, %ymm7;
vpxor (%rax), %ymm7, %ymm7; vpxor (%rax), %ymm7, %ymm7;
movq %r10, %rsp;
vpxor (0 * 32 + 16)(%rdx), %ymm6, %ymm6; vpxor (0 * 32 + 16)(%rdx), %ymm6, %ymm6;
vpxor (1 * 32 + 16)(%rdx), %ymm5, %ymm5; vpxor (1 * 32 + 16)(%rdx), %ymm5, %ymm5;
vpxor (2 * 32 + 16)(%rdx), %ymm4, %ymm4; vpxor (2 * 32 + 16)(%rdx), %ymm4, %ymm4;
...@@ -1047,6 +1045,7 @@ SYM_FUNC_START(camellia_cbc_dec_32way) ...@@ -1047,6 +1045,7 @@ SYM_FUNC_START(camellia_cbc_dec_32way)
vzeroupper; vzeroupper;
addq $(16 * 32), %rsp;
FRAME_END FRAME_END
ret; ret;
SYM_FUNC_END(camellia_cbc_dec_32way) SYM_FUNC_END(camellia_cbc_dec_32way)
...@@ -53,7 +53,7 @@ ...@@ -53,7 +53,7 @@
.endm .endm
.macro JMPTBL_ENTRY i .macro JMPTBL_ENTRY i
.word crc_\i - crc_array .quad crc_\i
.endm .endm
.macro JNC_LESS_THAN j .macro JNC_LESS_THAN j
...@@ -168,10 +168,7 @@ continue_block: ...@@ -168,10 +168,7 @@ continue_block:
xor crc2, crc2 xor crc2, crc2
## branch into array ## branch into array
lea jump_table(%rip), %bufp mov jump_table(,%rax,8), %bufp
movzwq (%bufp, %rax, 2), len
lea crc_array(%rip), %bufp
lea (%bufp, len, 1), %bufp
JMP_NOSPEC bufp JMP_NOSPEC bufp
################################################################ ################################################################
......
...@@ -645,9 +645,9 @@ _loop3: ...@@ -645,9 +645,9 @@ _loop3:
RESERVE_STACK = (W_SIZE*4 + 8+24) RESERVE_STACK = (W_SIZE*4 + 8+24)
/* Align stack */ /* Align stack */
mov %rsp, %rbx push %rbp
mov %rsp, %rbp
and $~(0x20-1), %rsp and $~(0x20-1), %rsp
push %rbx
sub $RESERVE_STACK, %rsp sub $RESERVE_STACK, %rsp
avx2_zeroupper avx2_zeroupper
...@@ -665,8 +665,8 @@ _loop3: ...@@ -665,8 +665,8 @@ _loop3:
avx2_zeroupper avx2_zeroupper
add $RESERVE_STACK, %rsp mov %rbp, %rsp
pop %rsp pop %rbp
pop %r15 pop %r15
pop %r14 pop %r14
......
...@@ -59,8 +59,6 @@ ...@@ -59,8 +59,6 @@
#define DATA_PTR %rsi /* 2nd arg */ #define DATA_PTR %rsi /* 2nd arg */
#define NUM_BLKS %rdx /* 3rd arg */ #define NUM_BLKS %rdx /* 3rd arg */
#define RSPSAVE %rax
/* gcc conversion */ /* gcc conversion */
#define FRAME_SIZE 32 /* space for 2x16 bytes */ #define FRAME_SIZE 32 /* space for 2x16 bytes */
...@@ -96,7 +94,8 @@ ...@@ -96,7 +94,8 @@
.text .text
.align 32 .align 32
SYM_FUNC_START(sha1_ni_transform) SYM_FUNC_START(sha1_ni_transform)
mov %rsp, RSPSAVE push %rbp
mov %rsp, %rbp
sub $FRAME_SIZE, %rsp sub $FRAME_SIZE, %rsp
and $~0xF, %rsp and $~0xF, %rsp
...@@ -288,7 +287,8 @@ SYM_FUNC_START(sha1_ni_transform) ...@@ -288,7 +287,8 @@ SYM_FUNC_START(sha1_ni_transform)
pextrd $3, E0, 1*16(DIGEST_PTR) pextrd $3, E0, 1*16(DIGEST_PTR)
.Ldone_hash: .Ldone_hash:
mov RSPSAVE, %rsp mov %rbp, %rsp
pop %rbp
ret ret
SYM_FUNC_END(sha1_ni_transform) SYM_FUNC_END(sha1_ni_transform)
......
...@@ -117,15 +117,13 @@ _XMM_SAVE_SIZE = 0 ...@@ -117,15 +117,13 @@ _XMM_SAVE_SIZE = 0
_INP_END_SIZE = 8 _INP_END_SIZE = 8
_INP_SIZE = 8 _INP_SIZE = 8
_CTX_SIZE = 8 _CTX_SIZE = 8
_RSP_SIZE = 8
_XFER = 0 _XFER = 0
_XMM_SAVE = _XFER + _XFER_SIZE _XMM_SAVE = _XFER + _XFER_SIZE
_INP_END = _XMM_SAVE + _XMM_SAVE_SIZE _INP_END = _XMM_SAVE + _XMM_SAVE_SIZE
_INP = _INP_END + _INP_END_SIZE _INP = _INP_END + _INP_END_SIZE
_CTX = _INP + _INP_SIZE _CTX = _INP + _INP_SIZE
_RSP = _CTX + _CTX_SIZE STACK_SIZE = _CTX + _CTX_SIZE
STACK_SIZE = _RSP + _RSP_SIZE
# rotate_Xs # rotate_Xs
# Rotate values of symbols X0...X3 # Rotate values of symbols X0...X3
...@@ -533,11 +531,11 @@ SYM_FUNC_START(sha256_transform_rorx) ...@@ -533,11 +531,11 @@ SYM_FUNC_START(sha256_transform_rorx)
pushq %r14 pushq %r14
pushq %r15 pushq %r15
mov %rsp, %rax push %rbp
mov %rsp, %rbp
subq $STACK_SIZE, %rsp subq $STACK_SIZE, %rsp
and $-32, %rsp # align rsp to 32 byte boundary and $-32, %rsp # align rsp to 32 byte boundary
mov %rax, _RSP(%rsp)
shl $6, NUM_BLKS # convert to bytes shl $6, NUM_BLKS # convert to bytes
jz done_hash jz done_hash
...@@ -704,7 +702,8 @@ only_one_block: ...@@ -704,7 +702,8 @@ only_one_block:
done_hash: done_hash:
mov _RSP(%rsp), %rsp mov %rbp, %rsp
pop %rbp
popq %r15 popq %r15
popq %r14 popq %r14
......
...@@ -76,14 +76,10 @@ tmp0 = %rax ...@@ -76,14 +76,10 @@ tmp0 = %rax
W_SIZE = 80*8 W_SIZE = 80*8
# W[t] + K[t] | W[t+1] + K[t+1] # W[t] + K[t] | W[t+1] + K[t+1]
WK_SIZE = 2*8 WK_SIZE = 2*8
RSPSAVE_SIZE = 1*8
GPRSAVE_SIZE = 5*8
frame_W = 0 frame_W = 0
frame_WK = frame_W + W_SIZE frame_WK = frame_W + W_SIZE
frame_RSPSAVE = frame_WK + WK_SIZE frame_size = frame_WK + WK_SIZE
frame_GPRSAVE = frame_RSPSAVE + RSPSAVE_SIZE
frame_size = frame_GPRSAVE + GPRSAVE_SIZE
# Useful QWORD "arrays" for simpler memory references # Useful QWORD "arrays" for simpler memory references
# MSG, DIGEST, K_t, W_t are arrays # MSG, DIGEST, K_t, W_t are arrays
...@@ -281,18 +277,18 @@ SYM_FUNC_START(sha512_transform_avx) ...@@ -281,18 +277,18 @@ SYM_FUNC_START(sha512_transform_avx)
test msglen, msglen test msglen, msglen
je nowork je nowork
# Save GPRs
push %rbx
push %r12
push %r13
push %r14
push %r15
# Allocate Stack Space # Allocate Stack Space
mov %rsp, %rax push %rbp
mov %rsp, %rbp
sub $frame_size, %rsp sub $frame_size, %rsp
and $~(0x20 - 1), %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: updateblock:
...@@ -353,15 +349,16 @@ updateblock: ...@@ -353,15 +349,16 @@ updateblock:
dec msglen dec msglen
jnz updateblock 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 # 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: nowork:
ret ret
......
...@@ -102,17 +102,13 @@ SRND_SIZE = 1*8 ...@@ -102,17 +102,13 @@ SRND_SIZE = 1*8
INP_SIZE = 1*8 INP_SIZE = 1*8
INPEND_SIZE = 1*8 INPEND_SIZE = 1*8
CTX_SIZE = 1*8 CTX_SIZE = 1*8
RSPSAVE_SIZE = 1*8
GPRSAVE_SIZE = 5*8
frame_XFER = 0 frame_XFER = 0
frame_SRND = frame_XFER + XFER_SIZE frame_SRND = frame_XFER + XFER_SIZE
frame_INP = frame_SRND + SRND_SIZE frame_INP = frame_SRND + SRND_SIZE
frame_INPEND = frame_INP + INP_SIZE frame_INPEND = frame_INP + INP_SIZE
frame_CTX = frame_INPEND + INPEND_SIZE frame_CTX = frame_INPEND + INPEND_SIZE
frame_RSPSAVE = frame_CTX + CTX_SIZE frame_size = frame_CTX + CTX_SIZE
frame_GPRSAVE = frame_RSPSAVE + RSPSAVE_SIZE
frame_size = frame_GPRSAVE + GPRSAVE_SIZE
## assume buffers not aligned ## assume buffers not aligned
#define VMOVDQ vmovdqu #define VMOVDQ vmovdqu
...@@ -570,18 +566,18 @@ frame_size = frame_GPRSAVE + GPRSAVE_SIZE ...@@ -570,18 +566,18 @@ frame_size = frame_GPRSAVE + GPRSAVE_SIZE
# "blocks" is the message length in SHA512 blocks # "blocks" is the message length in SHA512 blocks
######################################################################## ########################################################################
SYM_FUNC_START(sha512_transform_rorx) SYM_FUNC_START(sha512_transform_rorx)
# Save GPRs
push %rbx
push %r12
push %r13
push %r14
push %r15
# Allocate Stack Space # Allocate Stack Space
mov %rsp, %rax push %rbp
mov %rsp, %rbp
sub $frame_size, %rsp sub $frame_size, %rsp
and $~(0x20 - 1), %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 shl $7, NUM_BLKS # convert to bytes
jz done_hash jz done_hash
...@@ -672,15 +668,17 @@ loop2: ...@@ -672,15 +668,17 @@ loop2:
done_hash: 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 # 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 ret
SYM_FUNC_END(sha512_transform_rorx) SYM_FUNC_END(sha512_transform_rorx)
......
...@@ -74,14 +74,10 @@ tmp0 = %rax ...@@ -74,14 +74,10 @@ tmp0 = %rax
W_SIZE = 80*8 W_SIZE = 80*8
WK_SIZE = 2*8 WK_SIZE = 2*8
RSPSAVE_SIZE = 1*8
GPRSAVE_SIZE = 5*8
frame_W = 0 frame_W = 0
frame_WK = frame_W + W_SIZE frame_WK = frame_W + W_SIZE
frame_RSPSAVE = frame_WK + WK_SIZE frame_size = frame_WK + WK_SIZE
frame_GPRSAVE = frame_RSPSAVE + RSPSAVE_SIZE
frame_size = frame_GPRSAVE + GPRSAVE_SIZE
# Useful QWORD "arrays" for simpler memory references # Useful QWORD "arrays" for simpler memory references
# MSG, DIGEST, K_t, W_t are arrays # MSG, DIGEST, K_t, W_t are arrays
...@@ -283,18 +279,18 @@ SYM_FUNC_START(sha512_transform_ssse3) ...@@ -283,18 +279,18 @@ SYM_FUNC_START(sha512_transform_ssse3)
test msglen, msglen test msglen, msglen
je nowork je nowork
# Save GPRs
push %rbx
push %r12
push %r13
push %r14
push %r15
# Allocate Stack Space # Allocate Stack Space
mov %rsp, %rax push %rbp
mov %rsp, %rbp
sub $frame_size, %rsp sub $frame_size, %rsp
and $~(0x20 - 1), %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: updateblock:
...@@ -355,15 +351,16 @@ updateblock: ...@@ -355,15 +351,16 @@ updateblock:
dec msglen dec msglen
jnz updateblock 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 # 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: nowork:
ret ret
......
...@@ -21,17 +21,6 @@ ...@@ -21,17 +21,6 @@
#include <objtool/warn.h> #include <objtool/warn.h>
#include <arch/elf.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) static int is_x86_64(const struct elf *elf)
{ {
switch (elf->ehdr.e_machine) { switch (elf->ehdr.e_machine) {
...@@ -87,6 +76,31 @@ unsigned long arch_jump_destination(struct instruction *insn) ...@@ -87,6 +76,31 @@ unsigned long arch_jump_destination(struct instruction *insn)
return -1; \ return -1; \
else for (list_add_tail(&op->list, ops_list); op; op = NULL) 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, int arch_decode_instruction(const struct elf *elf, const struct section *sec,
unsigned long offset, unsigned int maxlen, unsigned long offset, unsigned int maxlen,
unsigned int *len, enum insn_type *type, unsigned int *len, enum insn_type *type,
...@@ -94,12 +108,14 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec, ...@@ -94,12 +108,14 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec,
struct list_head *ops_list) struct list_head *ops_list)
{ {
struct insn insn; struct insn insn;
int x86_64, sign, ret; int x86_64, ret;
unsigned char op1, op2, rex = 0, rex_b = 0, rex_r = 0, rex_w = 0, unsigned char op1, op2,
rex_x = 0, modrm = 0, modrm_mod = 0, modrm_rm = 0, rex = 0, rex_b = 0, rex_r = 0, rex_w = 0, rex_x = 0,
modrm_reg = 0, sib = 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 stack_op *op = NULL;
struct symbol *sym; struct symbol *sym;
u64 imm;
x86_64 = is_x86_64(elf); x86_64 = is_x86_64(elf);
if (x86_64 == -1) if (x86_64 == -1)
...@@ -132,23 +148,27 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec, ...@@ -132,23 +148,27 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec,
if (insn.modrm.nbytes) { if (insn.modrm.nbytes) {
modrm = insn.modrm.bytes[0]; modrm = insn.modrm.bytes[0];
modrm_mod = X86_MODRM_MOD(modrm); modrm_mod = X86_MODRM_MOD(modrm);
modrm_reg = X86_MODRM_REG(modrm); modrm_reg = X86_MODRM_REG(modrm) + 8*rex_r;
modrm_rm = X86_MODRM_RM(modrm); modrm_rm = X86_MODRM_RM(modrm) + 8*rex_b;
} }
if (insn.sib.nbytes) if (insn.sib.nbytes) {
sib = insn.sib.bytes[0]; 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) { switch (op1) {
case 0x1: case 0x1:
case 0x29: 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/sub reg, %rsp */
ADD_OP(op) { ADD_OP(op) {
op->src.type = OP_SRC_ADD; 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.type = OP_DEST_REG;
op->dest.reg = CFI_SP; op->dest.reg = CFI_SP;
} }
...@@ -160,7 +180,7 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec, ...@@ -160,7 +180,7 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec,
/* push reg */ /* push reg */
ADD_OP(op) { ADD_OP(op) {
op->src.type = OP_SRC_REG; 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; op->dest.type = OP_DEST_PUSH;
} }
...@@ -172,7 +192,7 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec, ...@@ -172,7 +192,7 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec,
ADD_OP(op) { ADD_OP(op) {
op->src.type = OP_SRC_POP; op->src.type = OP_SRC_POP;
op->dest.type = OP_DEST_REG; 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; break;
...@@ -190,12 +210,54 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec, ...@@ -190,12 +210,54 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec,
*type = INSN_JUMP_CONDITIONAL; *type = INSN_JUMP_CONDITIONAL;
break; break;
case 0x81: case 0x80 ... 0x83:
case 0x83: /*
if (rex != 0x48) * 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;
/* %rsp target only */
if (!rm_is_reg(CFI_SP))
break; break;
if (modrm == 0xe4) { 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 */ /* and imm, %rsp */
ADD_OP(op) { ADD_OP(op) {
op->src.type = OP_SRC_AND; op->src.type = OP_SRC_AND;
...@@ -205,53 +267,48 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec, ...@@ -205,53 +267,48 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec,
op->dest.reg = CFI_SP; op->dest.reg = CFI_SP;
} }
break; break;
}
if (modrm == 0xc4) default:
sign = 1; /* WARN ? */
else if (modrm == 0xec)
sign = -1;
else
break; 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; break;
case 0x89: case 0x89:
if (rex_w && !rex_r && modrm_reg == 4) { if (!rex_w)
break;
if (modrm_reg == CFI_SP) {
if (modrm_mod == 3) { if (mod_is_reg()) {
/* mov %rsp, reg */ /* mov %rsp, reg */
ADD_OP(op) { ADD_OP(op) {
op->src.type = OP_SRC_REG; op->src.type = OP_SRC_REG;
op->src.reg = CFI_SP; op->src.reg = CFI_SP;
op->dest.type = OP_DEST_REG; op->dest.type = OP_DEST_REG;
op->dest.reg = op_to_cfi_reg[modrm_rm][rex_b]; op->dest.reg = modrm_rm;
} }
break; break;
} else { } else {
/* skip nontrivial SIB */
if (modrm_rm == 4 && !(sib == 0x24 && rex_b == rex_x))
break;
/* skip RIP relative displacement */ /* skip RIP relative displacement */
if (modrm_rm == 5 && modrm_mod == 0) if (is_RIP())
break; break;
/* skip nontrivial SIB */
if (have_SIB()) {
modrm_rm = sib_base;
if (sib_index != CFI_SP)
break;
}
/* mov %rsp, disp(%reg) */ /* mov %rsp, disp(%reg) */
ADD_OP(op) { ADD_OP(op) {
op->src.type = OP_SRC_REG; op->src.type = OP_SRC_REG;
op->src.reg = CFI_SP; op->src.reg = CFI_SP;
op->dest.type = OP_DEST_REG_INDIRECT; 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; op->dest.offset = insn.displacement.value;
} }
break; break;
...@@ -260,12 +317,12 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec, ...@@ -260,12 +317,12 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec,
break; break;
} }
if (rex_w && !rex_b && modrm_mod == 3 && modrm_rm == 4) { if (rm_is_reg(CFI_SP)) {
/* mov reg, %rsp */ /* mov reg, %rsp */
ADD_OP(op) { ADD_OP(op) {
op->src.type = OP_SRC_REG; 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.type = OP_DEST_REG;
op->dest.reg = CFI_SP; op->dest.reg = CFI_SP;
} }
...@@ -274,13 +331,15 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec, ...@@ -274,13 +331,15 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec,
/* fallthrough */ /* fallthrough */
case 0x88: case 0x88:
if (!rex_b && if (!rex_w)
(modrm_mod == 1 || modrm_mod == 2) && modrm_rm == 5) { break;
if (rm_is_mem(CFI_BP)) {
/* mov reg, disp(%rbp) */ /* mov reg, disp(%rbp) */
ADD_OP(op) { ADD_OP(op) {
op->src.type = OP_SRC_REG; 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.type = OP_DEST_REG_INDIRECT;
op->dest.reg = CFI_BP; op->dest.reg = CFI_BP;
op->dest.offset = insn.displacement.value; op->dest.offset = insn.displacement.value;
...@@ -288,12 +347,12 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec, ...@@ -288,12 +347,12 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec,
break; break;
} }
if (rex_w && !rex_b && modrm_rm == 4 && sib == 0x24) { if (rm_is_mem(CFI_SP)) {
/* mov reg, disp(%rsp) */ /* mov reg, disp(%rsp) */
ADD_OP(op) { ADD_OP(op) {
op->src.type = OP_SRC_REG; 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.type = OP_DEST_REG_INDIRECT;
op->dest.reg = CFI_SP; op->dest.reg = CFI_SP;
op->dest.offset = insn.displacement.value; op->dest.offset = insn.displacement.value;
...@@ -304,7 +363,10 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec, ...@@ -304,7 +363,10 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec,
break; break;
case 0x8b: 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 */ /* mov disp(%rbp), reg */
ADD_OP(op) { ADD_OP(op) {
...@@ -312,11 +374,12 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec, ...@@ -312,11 +374,12 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec,
op->src.reg = CFI_BP; op->src.reg = CFI_BP;
op->src.offset = insn.displacement.value; op->src.offset = insn.displacement.value;
op->dest.type = OP_DEST_REG; 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 && if (rm_is_mem(CFI_SP)) {
modrm_mod != 3 && modrm_rm == 4) {
/* mov disp(%rsp), reg */ /* mov disp(%rsp), reg */
ADD_OP(op) { ADD_OP(op) {
...@@ -324,75 +387,48 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec, ...@@ -324,75 +387,48 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec,
op->src.reg = CFI_SP; op->src.reg = CFI_SP;
op->src.offset = insn.displacement.value; op->src.offset = insn.displacement.value;
op->dest.type = OP_DEST_REG; op->dest.type = OP_DEST_REG;
op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r]; op->dest.reg = modrm_reg;
} }
break;
} }
break; break;
case 0x8d: case 0x8d:
if (sib == 0x24 && rex_w && !rex_b && !rex_x) { if (mod_is_reg()) {
WARN("invalid LEA encoding at %s:0x%lx", sec->name, offset);
ADD_OP(op) { break;
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 && /* skip non 64bit ops */
insn.displacement.value == -8) { if (!rex_w)
break;
/* /* skip RIP relative displacement */
* lea -0x8(%r10), %rsp if (is_RIP())
* break;
* 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 && /* skip nontrivial SIB */
insn.displacement.value == -16) { if (have_SIB()) {
modrm_rm = sib_base;
if (sib_index != CFI_SP)
break;
}
/* /* lea disp(%src), %dst */
* lea -0x10(%r13), %rsp ADD_OP(op) {
* op->src.offset = insn.displacement.value;
* Restoring rsp back to its original value after a if (!op->src.offset) {
* stack realignment. /* lea (%src), %dst */
*/ op->src.type = OP_SRC_REG;
ADD_OP(op) { } else {
/* lea disp(%src), %dst */
op->src.type = OP_SRC_ADD; 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;
} }
op->src.reg = modrm_rm;
op->dest.type = OP_DEST_REG;
op->dest.reg = modrm_reg;
} }
break; break;
case 0x8f: case 0x8f:
...@@ -479,9 +515,17 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec, ...@@ -479,9 +515,17 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec,
* mov bp, sp * mov bp, sp
* pop bp * pop bp
*/ */
ADD_OP(op) ADD_OP(op) {
op->dest.type = OP_DEST_LEAVE; 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; break;
case 0xe3: case 0xe3:
......
...@@ -4,13 +4,13 @@ ...@@ -4,13 +4,13 @@
#define _OBJTOOL_CFI_REGS_H #define _OBJTOOL_CFI_REGS_H
#define CFI_AX 0 #define CFI_AX 0
#define CFI_DX 1 #define CFI_CX 1
#define CFI_CX 2 #define CFI_DX 2
#define CFI_BX 3 #define CFI_BX 3
#define CFI_SI 4 #define CFI_SP 4
#define CFI_DI 5 #define CFI_BP 5
#define CFI_BP 6 #define CFI_SI 6
#define CFI_SP 7 #define CFI_DI 7
#define CFI_R8 8 #define CFI_R8 8
#define CFI_R9 9 #define CFI_R9 9
#define CFI_R10 10 #define CFI_R10 10
......
...@@ -15,16 +15,23 @@ ...@@ -15,16 +15,23 @@
#include <subcmd/parse-options.h> #include <subcmd/parse-options.h>
#include <string.h> #include <string.h>
#include <stdlib.h>
#include <objtool/builtin.h> #include <objtool/builtin.h>
#include <objtool/objtool.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[] = { static const char * const check_usage[] = {
"objtool check [<options>] file.o", "objtool check [<options>] file.o",
NULL, NULL,
}; };
static const char * const env_usage[] = {
"OBJTOOL_ARGS=\"<options>\"",
NULL,
};
const struct option check_options[] = { const struct option check_options[] = {
OPT_BOOLEAN('f', "no-fp", &no_fp, "Skip frame pointer validation"), OPT_BOOLEAN('f', "no-fp", &no_fp, "Skip frame pointer validation"),
OPT_BOOLEAN('u', "no-unreachable", &no_unreachable, "Skip 'unreachable instruction' warnings"), OPT_BOOLEAN('u', "no-unreachable", &no_unreachable, "Skip 'unreachable instruction' warnings"),
...@@ -37,20 +44,44 @@ const struct option check_options[] = { ...@@ -37,20 +44,44 @@ const struct option check_options[] = {
OPT_BOOLEAN('n', "noinstr", &noinstr, "noinstr validation for vmlinux.o"), OPT_BOOLEAN('n', "noinstr", &noinstr, "noinstr validation for vmlinux.o"),
OPT_BOOLEAN('l', "vmlinux", &vmlinux, "vmlinux.o validation"), OPT_BOOLEAN('l', "vmlinux", &vmlinux, "vmlinux.o validation"),
OPT_BOOLEAN('M', "mcount", &mcount, "generate __mcount_loc"), OPT_BOOLEAN('M', "mcount", &mcount, "generate __mcount_loc"),
OPT_BOOLEAN('B', "backup", &backup, "create .orig files before modification"),
OPT_END(), 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) int cmd_check(int argc, const char **argv)
{ {
const char *objname; const char *objname;
struct objtool_file *file; struct objtool_file *file;
int ret; int ret;
argc = parse_options(argc, argv, check_options, check_usage, 0); argc = cmd_parse_options(argc, argv, check_usage);
if (argc != 1)
usage_with_options(check_usage, check_options);
objname = argv[0]; objname = argv[0];
file = objtool_open_read(objname); file = objtool_open_read(objname);
......
...@@ -34,10 +34,7 @@ int cmd_orc(int argc, const char **argv) ...@@ -34,10 +34,7 @@ int cmd_orc(int argc, const char **argv)
struct objtool_file *file; struct objtool_file *file;
int ret; int ret;
argc = parse_options(argc, argv, check_options, orc_usage, 0); argc = cmd_parse_options(argc, argv, orc_usage);
if (argc != 1)
usage_with_options(orc_usage, check_options);
objname = argv[0]; objname = argv[0];
file = objtool_open_read(objname); file = objtool_open_read(objname);
......
...@@ -108,6 +108,18 @@ static struct instruction *prev_insn_same_sym(struct objtool_file *file, ...@@ -108,6 +108,18 @@ static struct instruction *prev_insn_same_sym(struct objtool_file *file,
for (insn = next_insn_same_sec(file, insn); insn; \ for (insn = next_insn_same_sec(file, insn); insn; \
insn = next_insn_same_sec(file, 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) static bool is_sibling_call(struct instruction *insn)
{ {
/* /*
...@@ -120,7 +132,7 @@ 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. */ /* An indirect jump is either a sibling call or a jump to a table. */
if (insn->type == INSN_JUMP_DYNAMIC) 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. */ /* add_jump_destinations() sets insn->call_dest for sibling calls. */
return (is_static_jump(insn) && insn->call_dest); return (is_static_jump(insn) && insn->call_dest);
...@@ -1969,8 +1981,9 @@ static void restore_reg(struct cfi_state *cfi, unsigned char reg) ...@@ -1969,8 +1981,9 @@ static void restore_reg(struct cfi_state *cfi, unsigned char reg)
* 41 5d pop %r13 * 41 5d pop %r13
* c3 retq * c3 retq
*/ */
static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi, static int update_cfi_state(struct instruction *insn,
struct stack_op *op) struct instruction *next_insn,
struct cfi_state *cfi, struct stack_op *op)
{ {
struct cfi_reg *cfa = &cfi->cfa; struct cfi_reg *cfa = &cfi->cfa;
struct cfi_reg *regs = cfi->regs; struct cfi_reg *regs = cfi->regs;
...@@ -2029,7 +2042,7 @@ static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi, ...@@ -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 && 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 * mov %rbp, %rsp
...@@ -2171,7 +2184,7 @@ static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi, ...@@ -2171,7 +2184,7 @@ static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi,
break; 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", WARN_FUNC("unsupported stack register modification",
insn->sec, insn->offset); insn->sec, insn->offset);
return -1; return -1;
...@@ -2226,7 +2239,7 @@ static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi, ...@@ -2226,7 +2239,7 @@ static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi,
cfa->offset = 0; cfa->offset = 0;
cfi->drap_offset = -1; 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 */ /* pop %reg */
restore_reg(cfi, op->dest.reg); restore_reg(cfi, op->dest.reg);
...@@ -2367,26 +2380,6 @@ static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi, ...@@ -2367,26 +2380,6 @@ static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi,
break; 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: case OP_DEST_MEM:
if (op->src.type != OP_SRC_POP && op->src.type != OP_SRC_POPF) { if (op->src.type != OP_SRC_POP && op->src.type != OP_SRC_POPF) {
WARN_FUNC("unknown stack-related memory operation", WARN_FUNC("unknown stack-related memory operation",
...@@ -2443,13 +2436,15 @@ static int propagate_alt_cfi(struct objtool_file *file, struct instruction *insn ...@@ -2443,13 +2436,15 @@ static int propagate_alt_cfi(struct objtool_file *file, struct instruction *insn
return 0; 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; struct stack_op *op;
list_for_each_entry(op, &insn->stack_ops, list) { 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; return 1;
if (!insn->alt_group) if (!insn->alt_group)
...@@ -2732,7 +2727,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func, ...@@ -2732,7 +2727,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
return 0; return 0;
} }
if (handle_insn_ops(insn, &state)) if (handle_insn_ops(insn, next_insn, &state))
return 1; return 1;
switch (insn->type) { switch (insn->type) {
......
...@@ -35,7 +35,6 @@ enum op_dest_type { ...@@ -35,7 +35,6 @@ enum op_dest_type {
OP_DEST_MEM, OP_DEST_MEM,
OP_DEST_PUSH, OP_DEST_PUSH,
OP_DEST_PUSHF, OP_DEST_PUSHF,
OP_DEST_LEAVE,
}; };
struct op_dest { struct op_dest {
......
...@@ -8,7 +8,10 @@ ...@@ -8,7 +8,10 @@
#include <subcmd/parse-options.h> #include <subcmd/parse-options.h>
extern const struct option check_options[]; 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_check(int argc, const char **argv);
extern int cmd_orc(int argc, const char **argv); extern int cmd_orc(int argc, const char **argv);
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h>
#include <subcmd/exec-cmd.h> #include <subcmd/exec-cmd.h>
#include <subcmd/pager.h> #include <subcmd/pager.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -44,6 +45,64 @@ bool help; ...@@ -44,6 +45,64 @@ bool help;
const char *objname; const char *objname;
static struct objtool_file file; 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) struct objtool_file *objtool_open_read(const char *_objname)
{ {
if (objname) { if (objname) {
...@@ -59,6 +118,11 @@ struct objtool_file *objtool_open_read(const char *_objname) ...@@ -59,6 +118,11 @@ struct objtool_file *objtool_open_read(const char *_objname)
if (!file.elf) if (!file.elf)
return NULL; return NULL;
if (backup && !objtool_create_backup(objname)) {
WARN("can't create backup file");
return NULL;
}
INIT_LIST_HEAD(&file.insn_list); INIT_LIST_HEAD(&file.insn_list);
hash_init(file.insn_hash); hash_init(file.insn_hash);
INIT_LIST_HEAD(&file.retpoline_call_list); INIT_LIST_HEAD(&file.retpoline_call_list);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment