| # RUN: llvm-mc -triple=powerpc64le-unknown-linux-gnu -filetype=obj -o %t %s \ |
| # RUN: --defsym LE=1 |
| # RUN: llvm-jitlink -abs external_var=0xffff0000 -abs puts=0xffff6400 -abs \ |
| # RUN: foo=0xffff8800 -abs low_addr=0x0320 -noexec %t |
| # RUN: llvm-mc -triple=powerpc64-unknown-linux-gnu -filetype=obj -o %t %s |
| # RUN: llvm-jitlink -abs external_var=0xffff0000 -abs puts=0xffff6400 -abs \ |
| # RUN: foo=0xffff8800 -abs low_addr=0x0320 -noexec %t |
| # |
| # Check typical relocations involving external function call, external variable |
| # reference, local function call and referencing global variable defined in the |
| # same CU. This test serves as smoke test, `llvm-jitlink -check` is not used. |
| |
| .text |
| .abiversion 2 |
| .file "ppc64-relocs.c" |
| .globl main |
| .p2align 4 |
| .type main,@function |
| main: |
| .Lfunc_begin0: |
| li 3, 0 |
| blr |
| .long 0 |
| .quad 0 |
| .Lfunc_end0: |
| .size main, .Lfunc_end0-.Lfunc_begin0 |
| |
| .globl id |
| .p2align 4 |
| .type id,@function |
| id: |
| .Lfunc_begin1: |
| .Lfunc_gep1: |
| addis 2, 12, .TOC.-.Lfunc_gep1@ha |
| addi 2, 2, .TOC.-.Lfunc_gep1@l |
| .Lfunc_lep1: |
| .localentry id, .Lfunc_lep1-.Lfunc_gep1 |
| addis 4, 2, .LC0@toc@ha |
| ld 4, .LC0@toc@l(4) |
| lwz 4, 0(4) |
| sub 3, 4, 3 |
| extsw 3, 3 |
| blr |
| .long 0 |
| .quad 0 |
| .Lfunc_end1: |
| .size id, .Lfunc_end1-.Lfunc_begin1 |
| |
| # Test referencing external data via R_PPC64_TOC16HA and R_PPC64_TOC16LO. |
| .globl test_reference_external_data |
| .p2align 4 |
| .type test_reference_external_data,@function |
| test_reference_external_data: |
| .Lfunc_begin2: |
| .Lfunc_gep2: |
| addis 2, 12, .TOC.-.Lfunc_gep2@ha |
| addi 2, 2, .TOC.-.Lfunc_gep2@l |
| .Lfunc_lep2: |
| .localentry test_reference_external_data, .Lfunc_lep2-.Lfunc_gep2 |
| addis 3, 2, .LC0@toc@ha |
| ld 3, .LC0@toc@l(3) |
| blr |
| .long 0 |
| .quad 0 |
| .Lfunc_end2: |
| .size test_reference_external_data, .Lfunc_end2-.Lfunc_begin2 |
| |
| # Test referencing global variable defined in the same CU. |
| .globl test_reference_local_data |
| .p2align 4 |
| .type test_reference_local_data,@function |
| test_reference_local_data: |
| .Lfunc_begin3: |
| .Lfunc_gep3: |
| addis 2, 12, .TOC.-.Lfunc_gep3@ha |
| addi 2, 2, .TOC.-.Lfunc_gep3@l |
| .Lfunc_lep3: |
| .localentry test_reference_local_data, .Lfunc_lep3-.Lfunc_gep3 |
| addis 3, 2, .LC1@toc@ha |
| ld 3, .LC1@toc@l(3) |
| blr |
| .long 0 |
| .quad 0 |
| .Lfunc_end3: |
| .size test_reference_local_data, .Lfunc_end3-.Lfunc_begin3 |
| |
| # Test external function call with R_PPC64_REL24, which requires PLT |
| # call stub. |
| .globl test_external_call |
| .p2align 4 |
| .type test_external_call,@function |
| test_external_call: |
| .Lfunc_begin4: |
| .Lfunc_gep4: |
| addis 2, 12, .TOC.-.Lfunc_gep4@ha |
| addi 2, 2, .TOC.-.Lfunc_gep4@l |
| .Lfunc_lep4: |
| .localentry test_external_call, .Lfunc_lep4-.Lfunc_gep4 |
| mflr 0 |
| stdu 1, -32(1) |
| addis 3, 2, .L.str@toc@ha |
| std 0, 48(1) |
| addi 3, 3, .L.str@toc@l |
| bl puts |
| nop |
| addi 1, 1, 32 |
| ld 0, 16(1) |
| mtlr 0 |
| blr |
| .long 0 |
| .quad 0 |
| .Lfunc_end4: |
| .size test_external_call, .Lfunc_end4-.Lfunc_begin4 |
| |
| # Test local calls with R_PPC64_REL24. |
| # Calling to `id` has a nop followed, while there is no |
| # nop after calling `id1`. |
| .globl test_local_call |
| .p2align 4 |
| .type test_local_call,@function |
| test_local_call: |
| .Lfunc_begin5: |
| .Lfunc_gep5: |
| addis 2, 12, .TOC.-.Lfunc_gep5@ha |
| addi 2, 2, .TOC.-.Lfunc_gep5@l |
| .Lfunc_lep5: |
| .localentry test_local_call, .Lfunc_lep5-.Lfunc_gep5 |
| mflr 0 |
| std 29, -24(1) |
| std 30, -16(1) |
| stdu 1, -64(1) |
| std 0, 80(1) |
| mr 30, 3 |
| # A local call, with a nop followed. |
| bl id |
| nop |
| mr 29, 3 |
| mr 3, 30 |
| # A local call, without nop followed. |
| bl id1 |
| add 3, 3, 29 |
| extsw 3, 3 |
| addi 1, 1, 64 |
| ld 0, 16(1) |
| ld 30, -16(1) |
| ld 29, -24(1) |
| mtlr 0 |
| blr |
| .long 0 |
| .quad 0 |
| .Lfunc_end5: |
| .size test_local_call, .Lfunc_end5-.Lfunc_begin5 |
| |
| .p2align 4 |
| .type id1,@function |
| id1: |
| .Lfunc_begin6: |
| .Lfunc_gep6: |
| addis 2, 12, .TOC.-.Lfunc_gep6@ha |
| addi 2, 2, .TOC.-.Lfunc_gep6@l |
| .Lfunc_lep6: |
| .localentry id1, .Lfunc_lep6-.Lfunc_gep6 |
| addis 4, 2, .LC1@toc@ha |
| ld 4, .LC1@toc@l(4) |
| lwz 4, 0(4) |
| sub 3, 4, 3 |
| extsw 3, 3 |
| blr |
| .long 0 |
| .quad 0 |
| .Lfunc_end6: |
| .size id1, .Lfunc_end6-.Lfunc_begin6 |
| |
| # Test external function call with R_PPC64_REL24_NOTOC, which requires PLT |
| # call stub, however no saving of r2 is required and there's no nop after |
| # the branch instruction. |
| .globl bar |
| .p2align 4 |
| .type bar,@function |
| bar: |
| .Lfunc_begin7: |
| .localentry bar, 1 |
| b foo@notoc |
| #TC_RETURNd8 foo@notoc 0 |
| .long 0 |
| .quad 0 |
| .Lfunc_end7: |
| .size bar, .Lfunc_end7-.Lfunc_begin7 |
| |
| .global foobar |
| .p2align 4 |
| .type foobar,@function |
| foobar: |
| .Lfunc_begin8: |
| .localentry foobar, 1 |
| paddi 3, 0, .L.str@PCREL, 1 |
| blr |
| .Lfunc_end8: |
| .size foobar, .Lfunc_end8-.Lfunc_begin8 |
| |
| .global reloc_addr14 |
| .p2align 4 |
| .type reloc_addr14,@function |
| reloc_addr14: |
| .Lfunc_begin9: |
| bca 21, 30, low_addr |
| .Lfunc_end9: |
| .size reloc_addr14, .Lfunc_end9-.Lfunc_begin9 |
| |
| .global reloc_half16 |
| .p2align 4 |
| .type reloc_half16,@function |
| reloc_half16: |
| .Lfunc_begin10: |
| .ifdef LE |
| li 3, 0 |
| .reloc .Lfunc_begin10, R_PPC64_ADDR16_DS, low_addr |
| li 3, 0 |
| .reloc .Lfunc_begin10+4, R_PPC64_ADDR16_LO, low_addr |
| li 3, 0 |
| .reloc .Lfunc_begin10+8, R_PPC64_ADDR16_LO_DS, low_addr |
| li 3, 0 |
| .reloc .Lfunc_begin10+12, R_PPC64_ADDR16, low_addr |
| li 3, 0 |
| .reloc .Lfunc_begin10+16, R_PPC64_ADDR16_HI, low_addr |
| .else |
| li 3, 0 |
| .reloc .Lfunc_begin10+2, R_PPC64_ADDR16_DS, low_addr |
| li 3, 0 |
| .reloc .Lfunc_begin10+6, R_PPC64_ADDR16_LO, low_addr |
| li 3, 0 |
| .reloc .Lfunc_begin10+10, R_PPC64_ADDR16_LO_DS, low_addr |
| li 3, 0 |
| .reloc .Lfunc_begin10+14, R_PPC64_ADDR16, low_addr |
| li 3, 0 |
| .reloc .Lfunc_begin10+18, R_PPC64_ADDR16_HI, low_addr |
| .endif |
| li 3, low_addr@ha |
| li 3, low_addr@high |
| li 3, low_addr@higha |
| li 3, low_addr@higher |
| li 3, low_addr@highera |
| li 3, low_addr@highest |
| li 3, low_addr@highesta |
| .Ldelta16: |
| .ifdef LE |
| li 3, 0 |
| .reloc .Ldelta16, R_PPC64_REL16, reloc_half16 |
| li 3, 0 |
| .reloc .Ldelta16+4, R_PPC64_REL16_HI, reloc_half16 |
| li 3, 0 |
| .reloc .Ldelta16+8, R_PPC64_REL16_HA, reloc_half16 |
| li 3, 0 |
| .reloc .Ldelta16+12, R_PPC64_REL16_LO, reloc_half16 |
| .else |
| li 3, 0 |
| .reloc .Ldelta16+2, R_PPC64_REL16, reloc_half16 |
| li 3, 0 |
| .reloc .Ldelta16+6, R_PPC64_REL16_HI, reloc_half16 |
| li 3, 0 |
| .reloc .Ldelta16+10, R_PPC64_REL16_HA, reloc_half16 |
| li 3, 0 |
| .reloc .Ldelta16+14, R_PPC64_REL16_LO, reloc_half16 |
| .endif |
| .Ltocdetal16: |
| .ifdef LE |
| li 3, 0 |
| .reloc .Ltocdetal16, R_PPC64_TOC16, .L.str |
| li 3, 0 |
| .reloc .Ltocdetal16+4, R_PPC64_TOC16_HI, .L.str |
| li 3, 0 |
| .reloc .Ltocdetal16+8, R_PPC64_TOC16_DS, .L.str |
| li 3, 0 |
| .reloc .Ltocdetal16+12, R_PPC64_TOC16_HA, .L.str |
| li 3, 0 |
| .reloc .Ltocdetal16+16, R_PPC64_TOC16_LO, .L.str |
| li 3, 0 |
| .reloc .Ltocdetal16+20, R_PPC64_TOC16_LO_DS, .L.str |
| .else |
| li 3, 0 |
| .reloc .Ltocdetal16+2, R_PPC64_TOC16, .L.str |
| li 3, 0 |
| .reloc .Ltocdetal16+6, R_PPC64_TOC16_HI, .L.str |
| li 3, 0 |
| .reloc .Ltocdetal16+10, R_PPC64_TOC16_DS, .L.str |
| li 3, 0 |
| .reloc .Ltocdetal16+14, R_PPC64_TOC16_HA, .L.str |
| li 3, 0 |
| .reloc .Ltocdetal16+18, R_PPC64_TOC16_LO, .L.str |
| li 3, 0 |
| .reloc .Ltocdetal16+22, R_PPC64_TOC16_LO_DS, .L.str |
| .endif |
| blr |
| .Lfunc_end10: |
| .size reloc_half16, .Lfunc_end10-.Lfunc_begin10 |
| |
| .type local_var,@object |
| .section .bss,"aw",@nobits |
| .globl local_var |
| .p2align 2, 0x0 |
| local_var: |
| .long 0 |
| .size local_var, 4 |
| |
| .type .L.str,@object |
| .section .rodata.str1.1,"aMS",@progbits,1 |
| .L.str: |
| .asciz "Hey!" |
| .size .L.str, 5 |
| |
| .section .toc,"aw",@progbits |
| .LC0: |
| .tc external_var[TC],external_var |
| .LC1: |
| .tc local_var[TC],local_var |