This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] ld: add support for LOG2() in linker scripts


On Tue, Jul 23, 2013 at 04:01:32PM -0400, Hans-Peter Nilsson wrote:
> FWIW, I don't have any particularly strong opinion either way. Though
> I think you'd prefer going for the simplest solution and just have one
> function, when adding the missing test-cases. ;)

I went for the simplest solution still avoiding ambiguity. Please find
attached a patch implementing LOG2CEIL(x) rounding towards infinity. The
testcase is also included in the patch.

-- 
Clemens Lang
System Software Group, University of Erlangen-Nuremberg

>From 4adf1cf358e5169d42d76bafcccbacfaa4cf20b1 Mon Sep 17 00:00:00 2001
From: Clemens Lang <clemens.lang@fau.de>
Date: Wed, 24 Jul 2013 17:51:46 +0200
Subject: [PATCH] ld: add support for LOG2CEIL() in linker scripts

Adds a binary logarithm function usable in linker scripts. LOG2CEIL(x)
returns the logarithm of x, rounded up to the next integer. Returns
0 for x == 0.

This is useful for ARM devices using an MPU conforming to PMSAv7, e.g.,
the Cortex-M3, where MPU regions need to be aligned depending on their
size. Without the ability to compute logarithms in linker scripts, this
cannot be achieved in a single linking pass.
---
 ld/ChangeLog                     |    6 ++++++
 ld/NEWS                          |    2 ++
 ld/ld.texinfo                    |    5 +++++
 ld/ldexp.c                       |   23 +++++++++++++++++++++++
 ld/ldgram.y                      |    6 ++++--
 ld/ldlex.l                       |    1 +
 ld/testsuite/ld-scripts/log2.exp |   34 ++++++++++++++++++++++++++++++++++
 ld/testsuite/ld-scripts/log2.s   |    1 +
 ld/testsuite/ld-scripts/log2.t   |    8 ++++++++
 9 files changed, 84 insertions(+), 2 deletions(-)
 create mode 100644 ld/testsuite/ld-scripts/log2.exp
 create mode 100644 ld/testsuite/ld-scripts/log2.s
 create mode 100644 ld/testsuite/ld-scripts/log2.t

diff --git a/ld/ChangeLog b/ld/ChangeLog
index 4af9fca..b63f0bb 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,9 @@
+2013-07-24  Clemens Lang  <clemens.lang@fau.de>
+
+	* ldexp.c: Add LOG2CEIL() builtin function to linker script language
+	* ldgram.y: Likewise
+	* ldlex.l: Likewise
+
 2013-07-19  Sebastian Huber  <sebastian.huber@embedded-brains.de>
 
 	* ldgram.y: Add ALIGN_WITH_INPUT output section attribute.
diff --git a/ld/NEWS b/ld/NEWS
index d79c78f..5120036 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,5 +1,7 @@
 -*- text -*-
 
+* Add LOG2CEIL() builtin function to the linker script language
+
 * Add support for the Texas Instruments MSP430X processor.
 
 * Add support for Altera Nios II.
diff --git a/ld/ld.texinfo b/ld/ld.texinfo
index 986194b..00a0fa4 100644
--- a/ld/ld.texinfo
+++ b/ld/ld.texinfo
@@ -5947,6 +5947,11 @@ Return the length of the memory region named @var{memory}.
 Return the absolute LMA of the named @var{section}.  (@pxref{Output
 Section LMA}).
 
+@item LOG2CEIL(@var{exp})
+@kindex LOG2CEIL(@var{exp})
+Return the binary logarithm of @var{exp} rounded towards infinity.
+@code{LOG2CEIL(0)} returns 0.
+
 @kindex MAX
 @item MAX(@var{exp1}, @var{exp2})
 Returns the maximum of @var{exp1} and @var{exp2}.
diff --git a/ld/ldexp.c b/ld/ldexp.c
index ae3919b..e83812b 100644
--- a/ld/ldexp.c
+++ b/ld/ldexp.c
@@ -81,6 +81,7 @@ exp_print_token (token_code_type code, int infix_p)
     { GE, ">=" },
     { LSHIFT, "<<" },
     { RSHIFT, ">>" },
+    { LOG2CEIL, "LOG2CEIL" },
     { ALIGN_K, "ALIGN" },
     { BLOCK, "BLOCK" },
     { QUAD, "QUAD" },
@@ -143,6 +144,24 @@ make_abs (void)
 }
 
 static void
+make_log2ceil (void)
+{
+  bfd_vma value = expld.result.value;
+  bfd_vma result = 0;
+  /* if more than one bit is set in value, round up */
+  char round_up = (value != 1) && (value & 1) > 0;
+
+  while (value >>= 1)
+    {
+      round_up |= (value != 1) && (value & 1) > 0;
+      result++;
+    }
+  result += round_up;
+  expld.result.section = NULL;
+  expld.result.value = result;
+}
+
+static void
 new_abs (bfd_vma value)
 {
   expld.result.valid_p = TRUE;
@@ -242,6 +261,10 @@ fold_unary (etree_type *tree)
 	  make_abs ();
 	  break;
 
+	case LOG2CEIL:
+	  make_log2ceil ();
+	  break;
+
 	case '~':
 	  expld.result.value = ~expld.result.value;
 	  break;
diff --git a/ld/ldgram.y b/ld/ldgram.y
index 26cb677..4bf6bcd 100644
--- a/ld/ldgram.y
+++ b/ld/ldgram.y
@@ -147,8 +147,8 @@ static int error_index;
 %token ALIGNMOD AT SUBALIGN HIDDEN PROVIDE PROVIDE_HIDDEN AS_NEEDED
 %type <token> assign_op atype attributes_opt sect_constraint opt_align_with_input
 %type <name>  filename
-%token CHIP LIST SECT ABSOLUTE  LOAD NEWLINE ENDWORD ORDER NAMEWORD ASSERT_K
-%token FORMAT PUBLIC DEFSYMEND BASE ALIAS TRUNCATE REL
+%token CHIP LIST SECT ABSOLUTE LOAD NEWLINE ENDWORD ORDER NAMEWORD ASSERT_K
+%token LOG2CEIL FORMAT PUBLIC DEFSYMEND BASE ALIAS TRUNCATE REL
 %token INPUT_SCRIPT INPUT_MRI_SCRIPT INPUT_DEFSYM CASE EXTERN START
 %token <name> VERS_TAG VERS_IDENTIFIER
 %token GLOBAL LOCAL VERSIONK INPUT_VERSION_SCRIPT
@@ -1010,6 +1010,8 @@ exp	:
 			{ $$ = exp_nameop (ORIGIN, $3); }
 	|	LENGTH '(' NAME ')'
 			{ $$ = exp_nameop (LENGTH, $3); }
+	|	LOG2CEIL '(' exp ')'
+			{ $$ = exp_unop (LOG2CEIL, $3); }
 	;
 
 
diff --git a/ld/ldlex.l b/ld/ldlex.l
index 75be86d..86e8ab3 100644
--- a/ld/ldlex.l
+++ b/ld/ldlex.l
@@ -257,6 +257,7 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)*
 <EXPRESSION,BOTH,SCRIPT>"ALIGNOF"	{ RTOKEN(ALIGNOF); }
 <EXPRESSION,BOTH>"MAX"			{ RTOKEN(MAX_K); }
 <EXPRESSION,BOTH>"MIN"			{ RTOKEN(MIN_K); }
+<EXPRESSION,BOTH>"LOG2CEIL"			{ RTOKEN(LOG2CEIL); }
 <EXPRESSION,BOTH,SCRIPT>"ASSERT"	{ RTOKEN(ASSERT_K); }
 <BOTH,SCRIPT>"ENTRY"			{ RTOKEN(ENTRY);}
 <BOTH,SCRIPT,MRI>"EXTERN"		{ RTOKEN(EXTERN);}
diff --git a/ld/testsuite/ld-scripts/log2.exp b/ld/testsuite/ld-scripts/log2.exp
new file mode 100644
index 0000000..43827dc
--- /dev/null
+++ b/ld/testsuite/ld-scripts/log2.exp
@@ -0,0 +1,34 @@
+# Test LOG2() expression in linker script language.
+# By Clemens Lang
+#   Copyright 2013
+#   Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This program 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.
+#
+# This program 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+set testname "binary logarithm"
+
+if {![ld_assemble $as $srcdir/$subdir/log2.s tmpdir/log2.o]} {
+	unresolved $testname
+	return
+}
+
+if {![ld_simple_link $ld tmpdir/log2 "-T $srcdir/$subdir/log2.t tmpdir/log2.o"]} {
+	fail $testname
+} else {
+	pass $testname
+}
diff --git a/ld/testsuite/ld-scripts/log2.s b/ld/testsuite/ld-scripts/log2.s
new file mode 100644
index 0000000..f3f74ab
--- /dev/null
+++ b/ld/testsuite/ld-scripts/log2.s
@@ -0,0 +1 @@
+	.word 0
diff --git a/ld/testsuite/ld-scripts/log2.t b/ld/testsuite/ld-scripts/log2.t
new file mode 100644
index 0000000..abf73a9
--- /dev/null
+++ b/ld/testsuite/ld-scripts/log2.t
@@ -0,0 +1,8 @@
+ASSERT(LOG2CEIL(0) == 0,      "LOG2CEIL(0) == 0");
+ASSERT(LOG2CEIL(1) == 0,      "LOG2CEIL(1) == 0");
+ASSERT(LOG2CEIL(2) == 1,      "LOG2CEIL(2) == 1");
+ASSERT(LOG2CEIL(3) == 2,      "LOG2CEIL(3) == 2");
+ASSERT(LOG2CEIL(4) == 2,      "LOG2CEIL(4) == 2");
+ASSERT(LOG2CEIL(0x0ff) == 8,  "LOG2CEIL(0x0ff) == 8");
+ASSERT(LOG2CEIL(0x100) == 8,  "LOG2CEIL(0x100) == 8");
+ASSERT(LOG2CEIL(0x1ff) == 9,  "LOG2CEIL(0x1ff) == 9");
-- 
1.7.10.4


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]