gfids-gc.s 3.79 KB
# REQUIRES: x86
# RUN: llvm-mc -triple x86_64-windows-msvc %s -filetype=obj -o %t.obj
# RUN: lld-link %t.obj -guard:nolongjmp -out:%t.exe -opt:noref -entry:main
# RUN: llvm-readobj --file-headers --coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK-NOGC
# RUN: lld-link %t.obj -guard:nolongjmp -out:%t.exe -opt:noref -entry:main -debug:dwarf
# RUN: llvm-readobj --file-headers --coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK-NOGC
# RUN: lld-link %t.obj -guard:nolongjmp -out:%t.exe -opt:ref -entry:main
# RUN: llvm-readobj --file-headers --coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK-GC

# This assembly is meant to mimic what CL emits for this kind of C code when
# /Gw (-fdata-sections) is enabled:
# int f() { return 42; }
# int g() { return 13; }
# int (*fp1)() = &f;
# int (*fp2)() = &g;
# int main() {
#   return fp1();
# }
# Compile with 'cl -c -guard:cf -Gw -O1' and note the two associative .gfids$y
# sections.

# Expect 3 entries: main, f, and g.

# CHECK-NOGC: ImageBase: 0x140000000
# CHECK-NOGC: LoadConfig [
# CHECK-NOGC:   SEHandlerTable: 0x0
# CHECK-NOGC:   SEHandlerCount: 0
# CHECK-NOGC:   GuardCFCheckFunction: 0x0
# CHECK-NOGC:   GuardCFCheckDispatch: 0x0
# CHECK-NOGC:   GuardCFFunctionTable: 0x14000{{.*}}
# CHECK-NOGC:   GuardCFFunctionCount: 3
# CHECK-NOGC:   GuardFlags: 0x500
# CHECK-NOGC:   GuardAddressTakenIatEntryTable: 0x0
# CHECK-NOGC:   GuardAddressTakenIatEntryCount: 0
# CHECK-NOGC:   GuardLongJumpTargetTable: 0x0
# CHECK-NOGC:   GuardLongJumpTargetCount: 0
# CHECK-NOGC: ]
# CHECK-NOGC:      GuardFidTable [
# CHECK-NOGC-NEXT:   0x14000{{.*}}
# CHECK-NOGC-NEXT:   0x14000{{.*}}
# CHECK-NOGC-NEXT:   0x14000{{.*}}
# CHECK-NOGC-NEXT: ]

# Expect 2 entries: main and f. fp2 was discarded, so g was only used as a
# direct call target.

# CHECK-GC: ImageBase: 0x140000000
# CHECK-GC: LoadConfig [
# CHECK-GC:   SEHandlerTable: 0x0
# CHECK-GC:   SEHandlerCount: 0
# CHECK-GC:   GuardCFCheckFunction: 0x0
# CHECK-GC:   GuardCFCheckDispatch: 0x0
# CHECK-GC:   GuardCFFunctionTable: 0x14000{{.*}}
# CHECK-GC:   GuardCFFunctionCount: 2
# CHECK-GC:   GuardFlags: 0x500
# CHECK-GC:   GuardAddressTakenIatEntryTable: 0x0
# CHECK-GC:   GuardAddressTakenIatEntryCount: 0
# CHECK-GC:   GuardLongJumpTargetTable: 0x0
# CHECK-GC:   GuardLongJumpTargetCount: 0
# CHECK-GC: ]
# CHECK-GC:      GuardFidTable [
# CHECK-GC-NEXT:   0x14000{{.*}}
# CHECK-GC-NEXT:   0x14000{{.*}}
# CHECK-GC-NEXT: ]


# We need @feat.00 to have 0x800 to indicate .gfids are present.
        .def     @feat.00;
        .scl    3;
        .type   0;
        .endef
        .globl  @feat.00
@feat.00 = 0x801

        .def     main;
        .scl    2;
        .type   32;
        .endef
        .section        .text,"xr",one_only,main
        .globl  main
main:
        # Call g directly so that it is not dead stripped.
        callq g
        rex64 jmpq      *fp1(%rip)

        .def     f;
        .scl    3;
        .type   32;
        .endef
        .section        .text,"xr",one_only,f
f:
        movl $42, %eax
        retq

        .section        .data,"dw",one_only,fp1
        .globl  fp1
fp1:
        .quad   f

        .section        .gfids$y,"dr",associative,fp1
        .symidx f

# Section GC will remove the following, so 'g' should not be present in the
# guard fid table.

        .def     g;
        .scl    3;
        .type   32;
        .endef
        .section        .text,"xr",one_only,g
g:
        movl $13, %eax
        retq

        .section        .data,"dw",one_only,fp2
        .globl  fp2
fp2:
        .quad   g

        .section        .gfids$y,"dr",associative,fp2
        .symidx g

        .section .rdata,"dr"
.globl _load_config_used
_load_config_used:
        .long 256
        .fill 124, 1, 0
        .quad __guard_fids_table
        .quad __guard_fids_count
        .long __guard_flags
        .fill 128, 1, 0