// Darwin library definitions
// Copyright (C) Florian Negele

// This file is part of the Eigen Compiler Suite.

// The ECS is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// The ECS is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// Under Section 7 of the GNU General Public License version 3,
// the copyright holder grants you additional permissions to use
// this file as described in the ECS Runtime Support Exception.

// You should have received a copy of the GNU General Public License
// and a copy of the ECS Runtime Support Exception along with
// the ECS.  If not, see <https://www.gnu.org/licenses/>.

#ifndef ECS_DEF_DARWINLIB_HEADER_INCLUDED
#define ECS_DEF_DARWINLIB_HEADER_INCLUDED

#if defined __amd32__

	#define BASE 0x1000
	#define MAGIC MAGIC_32
	#define RELOCATION_LENGTH 2

	#define FUNCTION_CALL(name, parameters) \
		CODE (name) SHARED INSTR (pop ebx) INSTR (call dword [@_##name]) INSTR (jmp ebx)

#elif defined __amd64__

	#define BASE 0x1000
	#define MAGIC MAGIC_64
	#define RELOCATION_LENGTH 3

	#define FUNCTION_CALL(name, parameters) \
		CODE (name) SHARED INSTR (pop rbx) \
		IF (parameters > 0) INSTR (mov rdi, [rsp]) ENDIF \
		IF (parameters > 1) INSTR (mov rsi, [rsp + 8]) ENDIF \
		IF (parameters > 2) INSTR (mov rdx, [rsp + 16]) ENDIF \
		IF (parameters > 3) INSTR (mov rcx, [rsp + 24]) ENDIF \
		IF (parameters > 4) INSTR (mov r8, [rsp + 32]) ENDIF \
		IF (parameters > 5) INSTR (mov r9, [rsp + 40]) ENDIF \
		INSTR (mov r12, rsp) INSTR (and rsp, ~1111b) INSTR (call qword [rip + @_##name]) INSTR (mov rsp, r12) INSTR (jmp rbx)

#elif defined __arma64__

	#define BASE 0x1000
	#define MAGIC MAGIC_64
	#define RELOCATION_LENGTH 3

	#define FUNCTION_CALL(name, parameters) \
		INSTR (ldr x30, [sp], 16) INSTR (ret)

#else

	#error platform not supported

#endif

#include "macho"

#define LIBRARY(name, file) asm ( \
	HEADER (_dylib_command_##name) SHARED ALIGNMENT (ADDR_SIZE) GROUP (_commands) REQUIRE (_dysymtab_command) \
	DYLIB_COMMAND (LC_LOAD_DYLIB, DYLIB_COMMAND_SIZE + size - offset, offset, 0, 0, 0) LABEL (offset) BYTE (file, 0) ALIGN (ADDR_SIZE) LABEL (size) \
	);

#define FUNCTION(library, name, parameters) asm ( \
	TRAILER (_##name##_symbol) SHARED ALIGNMENT (ADDR_SIZE) GROUP (_symbol_table) REQUIRE (_dylib_command_##library) \
	NLIST (position (@_##name##_text) + 1, N_EXT, NO_SECT, 0, 0) \
	TRAILER (_##name##_text) SHARED GROUP (_text_table) BYTE ("_", #name, 0) \
	CONST (_##name##_relocation) SHARED ALIGNMENT (4) GROUP (_relocations) \
	RELOCATION_INFO (@_##name - BASE, index (@_##name##_symbol), 0, RELOCATION_LENGTH, 1, 0) \
	CONST (_##name) SHARED ALIGNMENT (ADDR_SIZE) REQUIRE (_##name##_relocation) RESERVE (ADDR_SIZE) \
	FUNCTION_CALL (name, parameters) \
	);

#endif // ECS_DEF_DARWINLIB_HEADER_INCLUDED
