# REQUIRES: aarch64

# RUN: rm -rf %t

## Ensure MTE globals doesn't work with REL (only RELA).
# RUN: yaml2obj %s -o %t.rel.o
# RUN: not ld.lld -shared --android-memtag-mode=sync %t.rel.o -o %t1.so 2>&1 | FileCheck %s --check-prefix=CHECK-RELA
# CHECK-RELA: non-RELA relocations are not allowed with memtag globals
--- !ELF
FileHeader:
  Class:           ELFCLASS64
  Data:            ELFDATA2LSB
  Type:            ET_REL
  Machine:         EM_AARCH64
  SectionHeaderStringTable: .strtab
Sections:
  - Name:            .text
    Type:            SHT_PROGBITS
    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
    AddressAlign:    0x4
    Content:         '00'
  - Name:            .data
    Type:            SHT_PROGBITS
    Flags:           [ SHF_WRITE, SHF_ALLOC ]
    AddressAlign:    0x10
    Content:         '00'
  - Name:            .memtag.globals.static
    Type:            SHT_AARCH64_MEMTAG_GLOBALS_STATIC
    AddressAlign:    0x1
  - Name:            .rel.memtag.globals.static
    Type:            SHT_REL
    Flags:           [ SHF_INFO_LINK ]
    Link:            .symtab
    AddressAlign:    0x8
    Info:            .memtag.globals.static
    Relocations:
      - Symbol:          four
        Type:            R_AARCH64_NONE
  - Type:            SectionHeaderTable
    Sections:
      - Name:            .strtab
      - Name:            .text
      - Name:            .data
      - Name:            .memtag.globals.static
      - Name:            .rel.memtag.globals.static
      - Name:            .symtab
Symbols:
  - Name:            four
    Type:            STT_OBJECT
    Section:         .data
    Binding:         STB_GLOBAL
    Value:           0x0
    Size:            0x10

## Functional testing for MTE globals.
# RUN: split-file %S/Inputs/aarch64-memtag-globals.s %t
# RUN: llvm-mc --filetype=obj -triple=aarch64-linux-android \
# RUN:   %t/input_1.s -o %t1.o
# RUN: llvm-mc --filetype=obj -triple=aarch64-linux-android \
# RUN:   %t/input_2.s -o %t2.o
# RUN: ld.lld -shared --android-memtag-mode=sync %t1.o %t2.o -o %t.so

## Normally relocations are printed before the symbol tables, so reorder it a
## bit to make it easier on matching addresses of relocations up with the
## symbols.
# RUN: llvm-readelf %t.so -s > %t.out
# RUN: llvm-readelf %t.so --section-headers --relocs --memtag >> %t.out
# RUN: FileCheck %s < %t.out
# RUN: llvm-objdump -Dz %t.so | FileCheck %s --check-prefix=CHECK-SPECIAL-RELOCS

## And ensure that --apply-dynamic-relocs is banned.
# RUN: not ld.lld --apply-dynamic-relocs -shared --android-memtag-mode=sync \
# RUN:   %t1.o %t2.o -o %t1.so 2>&1 | FileCheck %s --check-prefix=CHECK-DYNRELOC
# CHECK-DYNRELOC: --apply-dynamic-relocs cannot be used with MTE globals

## Ensure that fully statically linked executables just simply drop the MTE
## globals stuff: special relocations, data in the place to be relocated,
## dynamic entries, etc.
# RUN: llvm-mc --filetype=obj -triple=aarch64-linux-android \
# RUN:   %t/input_3.s -o %t3.o
# RUN: ld.lld -static --android-memtag-mode=sync %t1.o %t2.o %t3.o -o %t.static.so
# RUN: llvm-readelf -s --section-headers --relocs --memtag %t.static.so | \
# RUN:   FileCheck %s --check-prefix=CHECK-STATIC
# CHECK-STATIC-NOT: .memtag.globals.static
# CHECK-STATIC-NOT: DT_AARCH64_MEMTAG_

# CHECK-STATIC:      There are no relocations in this file
# CHECK-STATIC:      Memtag Dynamic Entries:
# CHECK-STATIC-NEXT: < none found >

# RUN: llvm-objdump -tDz %t.static.so | FileCheck %s --check-prefix=CHECK-STATIC-SPECIAL-RELOCS
# CHECK-STATIC-SPECIAL-RELOCS:      [[#%x,HIDDEN_GLOBAL_ADDR:]] {{.*}} .bss {{0*}}10 hidden_global
# CHECK-STATIC-SPECIAL-RELOCS:      <pointer_to_hidden_global_end>:
# CHECK-STATIC-SPECIAL-RELOCS-NEXT:   .word 0x{{0*}}[[#HIDDEN_GLOBAL_ADDR + 12]]
# CHECK-STATIC-SPECIAL-RELOCS-NEXT:   .word 0x00000000
# CHECK-STATIC-SPECIAL-RELOCS-NEXT:   .word 0x00000000
# CHECK-STATIC-SPECIAL-RELOCS-NEXT:   .word 0x00000000
# CHECK-STATIC-SPECIAL-RELOCS:      <pointer_past_hidden_global_end>:
# CHECK-STATIC-SPECIAL-RELOCS-NEXT:   .word 0x{{0*}}[[#HIDDEN_GLOBAL_ADDR + 16]]
# CHECK-STATIC-SPECIAL-RELOCS-NEXT:   .word 0x00000000
# CHECK-STATIC-SPECIAL-RELOCS-NEXT:   .word 0x00000000
# CHECK-STATIC-SPECIAL-RELOCS-NEXT:   .word 0x00000000

# CHECK:     Symbol table '.dynsym' contains
# CHECK-DAG: [[#%x,GLOBAL:]] 32 OBJECT GLOBAL DEFAULT [[#]] global{{$}}
# CHECK-DAG: [[#%x,GLOBAL_UNTAGGED:]] 4 OBJECT GLOBAL DEFAULT [[#]] global_untagged{{$}}
# CHECK-DAG: [[#%x,CONST_GLOBAL:]] 4 OBJECT GLOBAL DEFAULT [[#]] const_global{{$}}
# CHECK-DAG: [[#%x,GLOBAL_EXTERN:]] 16 OBJECT GLOBAL DEFAULT [[#]] global_extern{{$}}
# CHECK-DAG: [[#%x,GLOBAL_EXTERN_UNTAGGED:]] 4 OBJECT GLOBAL DEFAULT [[#]] global_extern_untagged{{$}}
# CHECK-DAG: 0 NOTYPE GLOBAL DEFAULT UND global_extern_outside_this_dso{{$}}
# CHECK-DAG: [[#%x,GLOBAL_EXTERN_CONST_DEFINITION_BUT_NONCONST_IMPORT:]] 4 OBJECT GLOBAL DEFAULT [[#]] global_extern_untagged_definition_but_tagged_import{{$}}
# CHECK-DAG: [[#%x,GLOBAL_EXTERN_UNTAGGED_DEFINITION_BUT_TAGGED_IMPORT:]] 4 OBJECT GLOBAL DEFAULT [[#]] global_extern_const_definition_but_nonconst_import{{$}}
# CHECK-DAG: [[#%x,POINTER_TO_GLOBAL:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_to_global{{$}}
# CHECK-DAG: [[#%x,POINTER_INSIDE_GLOBAL:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_inside_global{{$}}
# CHECK-DAG: [[#%x,POINTER_TO_GLOBAL_END:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_to_global_end{{$}}
# CHECK-DAG: [[#%x,POINTER_PAST_GLOBAL_END:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_past_global_end{{$}}
# CHECK-DAG: [[#%x,POINTER_TO_GLOBAL_UNTAGGED:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_to_global_untagged{{$}}
# CHECK-DAG: [[#%x,POINTER_TO_CONST_GLOBAL:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_to_const_global{{$}}
# CHECK-DAG: [[#%x,POINTER_TO_HIDDEN_CONST_GLOBAL:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_to_hidden_const_global{{$}}
# CHECK-DAG: [[#%x,POINTER_TO_HIDDEN_GLOBAL:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_to_hidden_global{{$}}
# CHECK-DAG: [[#%x,POINTER_TO_HIDDEN_GLOBAL_END:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_to_hidden_global_end{{$}}
# CHECK-DAG: [[#%x,POINTER_PAST_HIDDEN_GLOBAL_END:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_past_hidden_global_end{{$}}
# CHECK-DAG: [[#%x,POINTER_TO_HIDDEN_ATTR_GLOBAL:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_to_hidden_attr_global{{$}}
# CHECK-DAG: [[#%x,POINTER_TO_HIDDEN_ATTR_CONST_GLOBAL:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_to_hidden_attr_const_global{{$}}
# CHECK-DAG: [[#%x,POINTER_TO_GLOBAL_EXTERN:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_to_global_extern{{$}}
# CHECK-DAG: [[#%x,POINTER_TO_GLOBAL_EXTERN_UNTAGGED:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_to_global_extern_untagged{{$}}
# CHECK-DAG: [[#%x,POINTER_TO_GLOBAL_EXTERN_OUTSIDE_THIS_DSO:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_to_global_extern_outside_this_dso{{$}}
# CHECK-DAG: [[#%x,POINTER_TO_GLOBAL_EXTERN_CONST_DEFINITION_BUT_NONCONST_IMPORT:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_to_global_extern_const_definition_but_nonconst_import{{$}}
# CHECK-DAG: [[#%x,POINTER_TO_GLOBAL_EXTERN_UNTAGGED_DEFINITION_BUT_TAGGED_IMPORT:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_to_global_extern_untagged_definition_but_tagged_import{{$}}

# CHECK:     Symbol table '.symtab' contains
# CHECK-DAG: [[#%x,HIDDEN_CONST_GLOBAL:]] 4 OBJECT LOCAL DEFAULT [[#]] hidden_const_global{{$}}
# CHECK-DAG: [[#%x,HIDDEN_GLOBAL:]] 16 OBJECT LOCAL DEFAULT [[#]] hidden_global{{$}}
# CHECK-DAG: [[#%x,HIDDEN_ATTR_GLOBAL:]] 16 OBJECT LOCAL HIDDEN [[#]] hidden_attr_global{{$}}
# CHECK-DAG: [[#%x,HIDDEN_ATTR_CONST_GLOBAL:]] 4 OBJECT LOCAL HIDDEN [[#]] hidden_attr_const_global{{$}}

# CHECK:     Section Headers:
# CHECK:     .memtag.globals.dynamic AARCH64_MEMTAG_GLOBALS_DYNAMIC
# CHECK-NOT: .memtag.globals.static
# CHECK-NOT: AARCH64_MEMTAG_GLOBALS_STATIC

# CHECK: Relocation section '.rela.dyn'
# CHECK-DAG: [[#POINTER_TO_GLOBAL]] {{.*}} R_AARCH64_ABS64 {{.*}} global + 0
# CHECK-DAG: [[#POINTER_INSIDE_GLOBAL]] {{.*}} R_AARCH64_ABS64 {{.*}} global + 11
# CHECK-DAG: [[#POINTER_TO_GLOBAL_END]] {{.*}} R_AARCH64_ABS64 {{.*}} global + 1e
# CHECK-DAG: [[#POINTER_PAST_GLOBAL_END]] {{.*}} R_AARCH64_ABS64 {{.*}} global + 30
# CHECK-DAG: [[#POINTER_TO_GLOBAL_UNTAGGED]] {{.*}} R_AARCH64_ABS64 {{.*}} global_untagged + 0
# CHECK-DAG: [[#POINTER_TO_CONST_GLOBAL]] {{.*}} R_AARCH64_ABS64 {{.*}} const_global + 0

## RELATIVE relocations.
# CHECK-DAG: [[#POINTER_TO_HIDDEN_CONST_GLOBAL]] {{.*}} R_AARCH64_RELATIVE {{0*}}[[#HIDDEN_CONST_GLOBAL]]
# CHECK-DAG: [[#POINTER_TO_HIDDEN_GLOBAL]] {{.*}} R_AARCH64_RELATIVE {{0*}}[[#HIDDEN_GLOBAL]]

## AArch64 MemtagABI special RELATIVE relocation semantics, where the offset is encoded in the place.
# CHECK-DAG:                 [[#POINTER_TO_HIDDEN_GLOBAL_END]] {{.*}} R_AARCH64_RELATIVE {{0*}}[[#HIDDEN_GLOBAL + 12]]
# CHECK-SPECIAL-RELOCS:      <pointer_to_hidden_global_end>:
# CHECK-SPECIAL-RELOCS-NEXT:   .word 0x00000000
# CHECK-SPECIAL-RELOCS-NEXT:   .word 0x00000000
# CHECK-DAG:                 [[#POINTER_PAST_HIDDEN_GLOBAL_END]] {{.*}} R_AARCH64_RELATIVE {{0*}}[[#HIDDEN_GLOBAL + 16]]
# CHECK-SPECIAL-RELOCS:      <pointer_past_hidden_global_end>:
# CHECK-SPECIAL-RELOCS-NEXT:   .word 0xfffffff0
# CHECK-SPECIAL-RELOCS-NEXT:   .word 0xffffffff

## More ABS64 relocations.
# CHECK-DAG: [[#POINTER_TO_GLOBAL_EXTERN]] {{[0-9a-f]+}} R_AARCH64_ABS64 {{[0-9a-f]+}} global_extern + 0
# CHECK-DAG: [[#POINTER_TO_GLOBAL_EXTERN_UNTAGGED]] {{[0-9a-f]+}} R_AARCH64_ABS64 {{[0-9a-f]+}} global_extern_untagged + 0
# CHECK-DAG: [[#POINTER_TO_GLOBAL_EXTERN_OUTSIDE_THIS_DSO]] {{[0-9a-f]+}} R_AARCH64_ABS64 {{[0-9a-f]+}} global_extern_outside_this_dso + 0
# CHECK-DAG: [[#POINTER_TO_GLOBAL_EXTERN_CONST_DEFINITION_BUT_NONCONST_IMPORT]] {{[0-9a-f]+}} R_AARCH64_ABS64 {{[0-9a-f]+}} global_extern_const_definition_but_nonconst_import + 0
# CHECK-DAG: [[#POINTER_TO_GLOBAL_EXTERN_UNTAGGED_DEFINITION_BUT_TAGGED_IMPORT]] {{[0-9a-f]+}} R_AARCH64_ABS64 {{[0-9a-f]+}} global_extern_untagged_definition_but_tagged_import + 0

# CHECK:      Memtag Dynamic Entries
# CHECK-NEXT: AARCH64_MEMTAG_MODE: Synchronous (0)
# CHECK-NEXT: AARCH64_MEMTAG_HEAP: Disabled (0)
# CHECK-NEXT: AARCH64_MEMTAG_STACK: Disabled (0)
# CHECK-NEXT: AARCH64_MEMTAG_GLOBALS: 0x{{[0-9a-f]+}}
# CHECK-NEXT: AARCH64_MEMTAG_GLOBALSSZ: 23

# CHECK:      Memtag Android Note
# CHECK-NEXT: Tagging Mode: SYNC
# CHECK-NEXT: Heap: Disabled
# CHECK-NEXT: Stack: Disabled

## Global variable order hopefully isn't too brittle of a test here, but this allows us to make sure
## that we have all the global variables we expect, and no more.
# CHECK:      Memtag Global Descriptors:
# CHECK-NEXT: 0x[[#POINTER_TO_GLOBAL]]: 0x10
# CHECK-NEXT: 0x[[#POINTER_INSIDE_GLOBAL]]: 0x10
# CHECK-NEXT: 0x[[#POINTER_TO_GLOBAL_END]]: 0x10
# CHECK-NEXT: 0x[[#POINTER_PAST_GLOBAL_END]]: 0x10
# CHECK-NEXT: 0x[[#POINTER_TO_GLOBAL_UNTAGGED]]: 0x10
# CHECK-NEXT: 0x[[#POINTER_TO_CONST_GLOBAL]]: 0x10
# CHECK-NEXT: 0x[[#POINTER_TO_HIDDEN_CONST_GLOBAL]]: 0x10
# CHECK-NEXT: 0x[[#POINTER_TO_HIDDEN_GLOBAL]]: 0x10
# CHECK-NEXT: 0x[[#POINTER_TO_HIDDEN_ATTR_GLOBAL]]: 0x10
# CHECK-NEXT: 0x[[#POINTER_TO_HIDDEN_ATTR_CONST_GLOBAL]]: 0x10
# CHECK-NEXT: 0x[[#POINTER_TO_HIDDEN_GLOBAL_END]]: 0x10
# CHECK-NEXT: 0x[[#POINTER_PAST_HIDDEN_GLOBAL_END]]: 0x10
# CHECK-NEXT: 0x[[#POINTER_TO_GLOBAL_EXTERN]]: 0x10
# CHECK-NEXT: 0x[[#POINTER_TO_GLOBAL_EXTERN_UNTAGGED]]: 0x10
# CHECK-NEXT: 0x[[#POINTER_TO_GLOBAL_EXTERN_OUTSIDE_THIS_DSO]]: 0x10
# CHECK-NEXT: 0x[[#POINTER_TO_GLOBAL_EXTERN_CONST_DEFINITION_BUT_NONCONST_IMPORT]]: 0x10
# CHECK-NEXT: 0x[[#POINTER_TO_GLOBAL_EXTERN_UNTAGGED_DEFINITION_BUT_TAGGED_IMPORT]]: 0x10
# CHECK-NEXT: 0x[[#GLOBAL]]: 0x20
# CHECK-NEXT: 0x[[#HIDDEN_ATTR_GLOBAL]]: 0x10
# CHECK-NEXT: 0x[[#HIDDEN_GLOBAL]]: 0x10
# CHECK-NEXT: 0x[[#GLOBAL_EXTERN]]: 0x10
# CHECK-NOT:  0x
