llvm/llvm/test/ExecutionEngine/JITLink/ppc64/ppc64-relocs.s

# 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