# REQUIRES: system-linux

## Check that BOLT correctly parses the Linux kernel .altinstructions section
## and annotates alternative instructions.

# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o
# RUN: %clang %cflags -nostdlib %t.o -o %t.exe \
# RUN:   -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr,--no-pie
# RUN: llvm-bolt %t.exe --print-cfg --alt-inst-feature-size=2 -o %t.out \
# RUN:   | FileCheck %s

## Older kernels used to have padlen field in alt_instr. Check compatibility.

# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown --defsym PADLEN=1 \
# RUN:   %s -o %t.padlen.o
# RUN: %clang %cflags -nostdlib %t.padlen.o -o %t.padlen.exe \
# RUN:   -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr,--no-pie
# RUN: llvm-bolt %t.padlen.exe --print-cfg --alt-inst-has-padlen -o %t.padlen.out \
# RUN:   | FileCheck %s

## Check with a larger size of "feature" field in alt_instr.

# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown \
# RUN:   --defsym FEATURE_SIZE_4=1 %s -o %t.fs4.o
# RUN: %clang %cflags -nostdlib %t.fs4.o -o %t.fs4.exe \
# RUN:   -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr,--no-pie
# RUN: llvm-bolt %t.fs4.exe --print-cfg --alt-inst-feature-size=4 -o %t.fs4.out \
# RUN:   | FileCheck %s

## Check that out-of-bounds read is handled properly.

# RUN: not llvm-bolt %t.fs4.exe --alt-inst-feature-size=2 -o %t.fs4.out

## Check that BOLT automatically detects structure fields in .altinstructions.

# RUN: llvm-bolt %t.exe --print-cfg -o %t.out | FileCheck %s
# RUN: llvm-bolt %t.exe --print-cfg -o %t.padlen.out | FileCheck %s
# RUN: llvm-bolt %t.exe --print-cfg -o %t.fs4.out | FileCheck %s

# CHECK:      BOLT-INFO: Linux kernel binary detected
# CHECK:      BOLT-INFO: parsed 3 alternative instruction entries

  .text
  .globl _start
  .type _start, %function
_start:
# CHECK: Binary Function "_start"
.L0:
  rdtsc
# CHECK:      rdtsc
# CHECK-SAME: AltInst: 1
# CHECK-SAME: AltInst2: 2
# CHECK-SAME: AltInst3: 3
  nop
# CHECK-NEXT: nop
# CHECK-SAME: AltInst: 1
# CHECK-SAME: AltInst2: 2
# CHECK-SAME: AltInst3: 3
  nop
  nop
.L1:
  ret
  .size _start, .-_start

  .section .altinstr_replacement,"ax",@progbits
.A0:
  lfence
  rdtsc
.A1:
  rdtscp
.A2:
  pushf
  pop %rax
.Ae:

## Alternative instruction info.
  .section .altinstructions,"a",@progbits

  .long .L0 - .   # org instruction
  .long .A0 - .   # alt instruction
.ifdef FEATURE_SIZE_4
  .long 0x72      # feature flags
.else
  .word 0x72      # feature flags
.endif
  .byte .L1 - .L0 # org size
  .byte .A1 - .A0 # alt size
.ifdef PADLEN
  .byte 0
.endif

  .long .L0 - .   # org instruction
  .long .A1 - .   # alt instruction
.ifdef FEATURE_SIZE_4
  .long 0x3b      # feature flags
.else
  .word 0x3b      # feature flags
.endif
  .byte .L1 - .L0 # org size
  .byte .A2 - .A1 # alt size
.ifdef PADLEN
  .byte 0
.endif

  .long .L0 - .   # org instruction
  .long .A2 - .   # alt instruction
.ifdef FEATURE_SIZE_4
  .long 0x110     # feature flags
.else
  .word 0x110     # feature flags
.endif
  .byte .L1 - .L0 # org size
  .byte .Ae - .A2 # alt size
.ifdef PADLEN
  .byte 0
.endif

## ORC unwind for "pushf; pop %rax" alternative sequence.
  .section .orc_unwind,"a",@progbits
  .align 4
  .section .orc_unwind_ip,"a",@progbits
  .align 4

  .section .orc_unwind
  .2byte 8
  .2byte 0
  .2byte 0x205
  .section .orc_unwind_ip
  .long _start - .

  .section .orc_unwind
  .2byte 16
  .2byte 0
  .2byte 0x205
  .section .orc_unwind_ip
  .long .L0 + 1 - .

  .section .orc_unwind
  .2byte 8
  .2byte 0
  .2byte 0x205
  .section .orc_unwind_ip
  .long .L0 + 2 - .

## Linux kernel version
  .rodata
  .align 16
  .globl linux_banner
  .type  linux_banner, @object
linux_banner:
  .string  "Linux version 6.6.61\n"
  .size  linux_banner, . - linux_banner

## Fake Linux Kernel sections.
  .section __ksymtab,"a",@progbits
  .section __ksymtab_gpl,"a",@progbits
