[Skiboot] [PATCH 1/2] Initial support for the ELFv2 ABI

Nicholas Piggin npiggin at gmail.com
Thu Jan 5 20:35:47 AEDT 2017


Provide an experimental option to compile using ELFv2 ABI even on big
endian builds. ELFv2 + BE is not officially supported by the toolchain,
but it works quite well. It may be useful as a small step toward a
little-endian build.

This saves about 200kB of text/data.

Signed-off-by: Nicholas Piggin <npiggin at gmail.com>
---
 Makefile          |  8 +++++++
 Makefile.main     | 11 ++++++++-
 asm/head.S        |  1 +
 core/init.c       | 18 ++++++++++-----
 core/opal.c       |  8 +++----
 include/elf-abi.h | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 101 insertions(+), 12 deletions(-)
 create mode 100644 include/elf-abi.h

diff --git a/Makefile b/Makefile
index f13bf50f..d4a097f7 100644
--- a/Makefile
+++ b/Makefile
@@ -38,6 +38,14 @@ KERNEL ?=
 STACK_CHECK ?= $(DEBUG)
 
 #
+# Experimental (unsupported) build options
+#
+# Little-endian does not yet build. Include it here to set ELF ABI.
+LITTLE_ENDIAN ?= 0
+# ELF v2 ABI is more efficient and compact
+ELF_ABI_v2 ?= $(LITTLE_ENDIAN)
+
+#
 # Where is the source directory, must be a full path (no ~)
 # Example: SRC= /home/me/skiboot
 #
diff --git a/Makefile.main b/Makefile.main
index d71635b1..5656cb72 100644
--- a/Makefile.main
+++ b/Makefile.main
@@ -71,8 +71,12 @@ endif
 CFLAGS := -fno-strict-aliasing -pie -mbig-endian -m64
 CFLAGS += -Wl,--oformat,elf64-powerpc
 CFLAGS += -ffixed-r13
-CFLAGS += $(call try-cflag,$(CC),-mabi=elfv1)
 CFLAGS += $(call try-cflag,$(CC),-std=gnu11)
+ifeq ($(ELF_ABI_v2),1)
+CFLAGS += $(call try-cflag,$(CC),-mabi=elfv2)
+else
+CFLAGS += $(call try-cflag,$(CC),-mabi=elfv1)
+endif
 
 ifeq ($(SKIBOOT_GCOV),1)
 CFLAGS += -fprofile-arcs -ftest-coverage -DSKIBOOT_GCOV=1
@@ -109,6 +113,11 @@ LDRFLAGS=-melf64ppc
 #LDFLAGS += -Wl,-v -Wl,-Map,foomap 
 
 AFLAGS := -D__ASSEMBLY__ -mbig-endian -m64
+ifeq ($(ELF_ABI_v2),1)
+AFLAGS += $(call try-cflag,$(CC),-mabi=elfv2)
+else
+AFLAGS += $(call try-cflag,$(CC),-mabi=elfv1)
+endif
 
 # Special tool flags:
 # Do not use the floating point unit
diff --git a/asm/head.S b/asm/head.S
index 43fb93f5..a2ab23dc 100644
--- a/asm/head.S
+++ b/asm/head.S
@@ -896,6 +896,7 @@ opal_entry:
 
 	/* Convert our token into a table entry and get the
 	 * function pointer. Also check the token.
+	 * For ELFv2 ABI, the local entry point is used so no need for r12.
 	 */
 	cmpldi	%r0,OPAL_LAST
 	bgt-	2f
diff --git a/core/init.c b/core/init.c
index 81939dd0..5b49233b 100644
--- a/core/init.c
+++ b/core/init.c
@@ -607,12 +607,6 @@ static void dt_init_misc(void)
 	dt_fixups();
 }
 
-static void branch_null(void)
-{
-	assert_fail("Branch to NULL !");
-}
-
-
 typedef void (*ctorcall_t)(void);
 
 static void __nomcount do_ctors(void)
@@ -624,6 +618,13 @@ static void __nomcount do_ctors(void)
 		(*call)();
 }
 
+#ifndef PPC64_ELF_ABI_v2
+static void branch_null(void)
+{
+	assert_fail("Branch to NULL !");
+}
+
+
 static void setup_branch_null_catcher(void)
 {
        void (*bn)(void) = branch_null;
@@ -635,6 +636,11 @@ static void setup_branch_null_catcher(void)
         */
        memcpy(0, bn, 16);
 }
+#else
+static void setup_branch_null_catcher(void)
+{
+}
+#endif
 
 void setup_reset_vector(void)
 {
diff --git a/core/opal.c b/core/opal.c
index 1d15abea..6087e65a 100644
--- a/core/opal.c
+++ b/core/opal.c
@@ -29,6 +29,7 @@
 #include <affinity.h>
 #include <opal-msg.h>
 #include <timer.h>
+#include <elf-abi.h>
 
 /* Pending events to signal via opal_poll_events */
 uint64_t opal_pending_events;
@@ -58,8 +59,7 @@ void opal_table_init(void)
 	printf("OPAL table: %p .. %p, branch table: %p\n",
 	       s, e, opal_branch_table);
 	while(s < e) {
-		uint64_t *func = s->func;
-		opal_branch_table[s->token] = *func;
+		opal_branch_table[s->token] = function_entry_address(s->func);
 		opal_num_args[s->token] = s->nargs;
 		s++;
 	}
@@ -113,11 +113,9 @@ void opal_trace_entry(struct stack_frame *eframe)
 
 void __opal_register(uint64_t token, void *func, unsigned int nargs)
 {
-	uint64_t *opd = func;
-
 	assert(token <= OPAL_LAST);
 
-	opal_branch_table[token] = *opd;
+	opal_branch_table[token] = function_entry_address(func);
 	opal_num_args[token] = nargs;
 }
 
diff --git a/include/elf-abi.h b/include/elf-abi.h
new file mode 100644
index 00000000..e8397f70
--- /dev/null
+++ b/include/elf-abi.h
@@ -0,0 +1,67 @@
+/* Copyright 2017 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * 	http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ELF_ABI_H
+#define __ELF_ABI_H
+
+#ifndef __ASSEMBLY__
+
+#if defined (_CALL_ELF) && _CALL_ELF == 2
+#define ELF_ABI_v2
+#else
+#define ELF_ABI_v1
+#endif
+
+/* From linux/arch/powerpc/include/asm/code-patching.h */
+#define OP_RT_RA_MASK   0xffff0000UL
+#define LIS_R2          0x3c020000UL
+#define ADDIS_R2_R12    0x3c4c0000UL
+#define ADDI_R2_R2      0x38420000UL
+
+static inline uint64_t function_entry_address(void *func)
+{
+#ifdef ELF_ABI_v2
+	u32 *insn = func;
+	/*
+	 * A PPC64 ABIv2 function may have a local and a global entry
+	 * point. We use the local entry point for branch tables called
+	 * from asm, only a single TOC is used, so identify and step over
+	 * the global entry point sequence.
+	 *
+	 * The global entry point sequence is always of the form:
+	 *
+	 * addis r2,r12,XXXX
+	 * addi  r2,r2,XXXX
+	 *
+	 * A linker optimisation may convert the addis to lis:
+	 *
+	 * lis   r2,XXXX
+	 * addi  r2,r2,XXXX
+	 */
+	if ((((*insn & OP_RT_RA_MASK) == ADDIS_R2_R12) ||
+	     ((*insn & OP_RT_RA_MASK) == LIS_R2)) &&
+	    ((*(insn+1) & OP_RT_RA_MASK) == ADDI_R2_R2))
+		return (uint64_t)(insn + 2);
+	else
+		return (uint64_t)func;
+#else
+	return *(uint64_t *)func;
+#endif
+}
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __COMPILER_H */
-- 
2.11.0



More information about the Skiboot mailing list