[v1,5/7] SECTOR: language additions

Message ID 20230310000817.751962-6-binutils@emagii.com
State Accepted
Headers
Series [v1,1/7] SECTOR: NEWS |

Checks

Context Check Description
snail/binutils-gdb-check success Github commit url

Commit Message

Ulf Samuelsson March 10, 2023, 12:08 a.m. UTC
  From: Ulf Samuelsson <ulf@emagii.com>

Signed-off-by: Ulf Samuelsson <ulf@emagii.com>
---
 ld/lddigest.h  |   7 ++
 ld/ldsectors.c | 309 +++++++++++++++++++++++++++++++++++++++++++++++++
 ld/sysdep.h    |   2 +
 3 files changed, 318 insertions(+)
 create mode 100644 ld/ldsectors.c
  

Patch

diff --git a/ld/lddigest.h b/ld/lddigest.h
index 8f2889f1846..95e442006ef 100755
--- a/ld/lddigest.h
+++ b/ld/lddigest.h
@@ -189,4 +189,11 @@  extern void lang_generate_crc
 extern void lang_generate_digest
   (void);
 
+extern void lang_add_bank
+  (const char *name);
+extern void lang_add_sector
+  (const char *size);
+extern void lang_align_sector
+  (void);
+
 #endif /* LDDIGEST_H */
diff --git a/ld/ldsectors.c b/ld/ldsectors.c
new file mode 100644
index 00000000000..c9e1fcb8756
--- /dev/null
+++ b/ld/ldsectors.c
@@ -0,0 +1,309 @@ 
+/* Linker command language support.
+   Copyright (C) 1991-2023 Ulf Samuelsson <ulf@emagii.com>
+
+   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.  */
+
+#define _GNU_SOURCE
+#include "sysdep.h"
+#include "bfd.h"
+#include "safe-ctype.h"
+#include "obstack.h"
+#include "bfdlink.h"
+#include "ctf-api.h"
+
+#include "ld.h"
+#include "ldmain.h"
+#include "ldexp.h"
+#include "ldlang.h"
+#include <ldgram.h>
+#include "ldlex.h"
+#include "ldmisc.h"
+#include "lddigest.h"
+
+typedef struct
+{
+  const char *name;
+  int count;
+  int location;
+} bank_t;
+
+typedef struct symbol
+{
+  uint64_t value;
+  char *str;
+} symbol_t;
+
+typedef struct sector
+{
+  symbol_t begin;
+  symbol_t end;
+  symbol_t size;
+  const char *name;
+} sector_t;
+
+typedef struct list list_t;
+struct list
+{
+  list_t *next;
+  void *data;
+};
+
+typedef struct
+{
+  list_t *first;
+  list_t *last;
+  char *name;
+} head_t;
+
+bank_t dummy_bank = {.name = "dummy",.count = 0 };
+list_t dummy_bank_l = {.next = NULL,.data = (void *) &dummy_bank };
+head_t banks = { &dummy_bank_l, &dummy_bank_l, "banks" };
+
+sector_t dummy_sector = {
+  .begin = {0, NULL},
+  .end = {0, NULL},
+  .size = {0, NULL},
+  .name = NULL
+};
+list_t dummy_sector_l = {.next = NULL,.data = (void *) &dummy_sector };
+head_t sectors = { &dummy_sector_l, &dummy_sector_l, "sectors" };
+
+#if 0
+static void
+print_symbol (symbol_t * s)
+{
+  if (s != NULL)
+    {
+      printf ("%-32s= 0x%016lx;\n", s->str, s->value);
+    }
+}
+
+static void
+print_sector (sector_t * s)
+{
+  print_symbol (&s->begin);
+  print_symbol (&s->end);
+  print_symbol (&s->size);
+}
+#endif
+
+static list_t *
+list_add_to_end (head_t * h, void *element)
+{
+  list_t *e = (list_t *) malloc (sizeof (list_t));
+  if (e != NULL)
+    {
+      e->next = NULL;
+      e->data = element;
+      if (h->first == NULL)
+	{
+	  h->first = e;
+	}
+      h->last->next = (void *) e;
+      h->last = (void *) e;
+    }
+  return e;
+}
+
+void
+lang_add_bank (const char *name)
+{
+  bank_t *b = malloc (sizeof (bank_t));
+  list_t *l;
+  if (b == NULL)
+    {
+      einfo (_("%F%P: can not allocate memory for memory bank list: %E\n"));
+      return;
+    }
+  b->name = name;
+  b->count = 0;
+  l = list_add_to_end (&banks, (void *) b);
+  if (l == NULL)
+    {
+      einfo (_("%F%P: can not allocate memory for memory bank: %E\n"));
+    }
+}
+
+void
+lang_add_sector (const char *size)
+{
+  char *p, c;
+  bank_t *b;
+  uint64_t val = strtoull (size, &p, 10);
+  if (errno == ERANGE)
+    return;
+  /* Skip whitespace */
+  while ((c = *p) != 0)
+    {
+      if (c <= ' ')
+	{
+	  p++;
+	}
+      else
+	{
+	  break;
+	}
+    }
+
+  /* Translate to upper case */
+  {
+    char *tmpp = p;
+
+    while ((c = *tmpp) != 0)
+      {
+	if ((c >= 'a') && (c <= 'z'))
+	  {
+	    c = c - 'a' + 'A';
+	    *tmpp = c;
+	  }
+	tmpp++;
+      }
+  }
+
+  /* check for multipliers */
+  if (!strcmp (p, "BYTES"))
+    {
+      val *= 1;
+    }
+  else if (!strcmp (p, "KB"))
+    {
+      val *= 1024;
+    }
+  else if (!strcmp (p, "MB"))
+    {
+      val *= 1024 * 1024;
+    }
+
+  /* Create a sector record - unless dummy sector */
+  b = banks.last->data;
+  if (strncmp (b->name, "dummy", 5))
+    {
+      size_t len;
+      list_t *l;
+      sector_t *s = malloc (sizeof (sector_t));
+      if (s == NULL)
+	{
+	  einfo (_("%F%P: can not allocate memory for sector list: %E\n"));
+	  return;
+	}
+
+      s->begin.value = b->location;
+      len = asprintf (&s->begin.str, "%s#%02d#begin", b->name, b->count);
+      s->end.value = b->location + val;
+      len += asprintf (&s->end.str, "%s#%02d#end", b->name, b->count);
+      s->size.value = val;
+      len += asprintf (&s->size.str, "%s#%02d#size", b->name, b->count);
+      if (len <= 1)
+	{
+	};			/* 'Use' "len" to avoid warnings */
+      l = list_add_to_end (&sectors, (void *) s);
+      if (l == NULL)
+	{
+	  einfo (_("%F%P: can not allocate memory for sector: %E\n"));
+	}
+    }
+  b->location += val;
+  b->count++;
+}
+
+static etree_type *
+dot (void)
+{
+  return exp_nameop (NAME, ".");
+}
+
+static etree_type *
+begin_s (sector_t * s)
+{
+  return exp_nameop (NAME, s->begin.str);
+}
+
+static etree_type *
+end_s (sector_t * s)
+{
+  return exp_nameop (NAME, s->end.str);
+}
+
+static etree_type *
+size_s (sector_t * s)
+{
+  return exp_nameop (NAME, s->size.str);
+}
+
+static void
+define_symbol (symbol_t * symbol)
+{
+  etree_type *value = exp_bigintop ((bfd_vma) symbol->value, NULL);
+  lang_add_assignment (exp_assign (symbol->str, value, true));
+}
+
+static void
+define_sector (sector_t * s)
+{
+  define_symbol (&s->begin);
+  define_symbol (&s->end);
+  define_symbol (&s->size);
+}
+
+static bool
+define_sectors (void)
+{
+  sector_t *s;
+  bool present = false;
+  for (list_t * sl = sectors.first->next; sl != NULL; sl = sl->next)
+    {
+      s = (sector_t *) sl->data;
+      define_sector (s);
+      present = true;
+    }
+  return present;
+}
+
+static void
+cond_align_to_sector (sector_t * s)
+{
+  /*
+   * Align, if location is within the sector
+   * . = ( (. <= begin) && (. <= end) ) ? ALIGN(size) : . ;
+   */
+  etree_type *lower = exp_binop (GE, dot (), begin_s (s));
+  etree_type *upper = exp_binop (LE, dot (), end_s (s));
+  etree_type *in_range = exp_binop (ANDAND, lower, upper);
+  etree_type *align = exp_unop (ALIGN_K, size_s (s));
+  etree_type *expr = exp_trinop ('?', in_range, align, dot ());
+  lang_add_assignment (exp_assign (".", expr, false));
+}
+
+void
+lang_align_sector (void)
+{
+  static bool defined = false;
+  if (!defined)
+    {
+      defined = define_sectors ();
+    }
+  if (!defined)
+    {
+      einfo (_("%F%P: 'ALIGN_SECTOR' needs to be preceeded by a"
+	       " 'BANK' command\n"));
+    }
+  for (list_t * sl = sectors.first->next; sl != NULL; sl = sl->next)
+    {
+      cond_align_to_sector ((sector_t *) sl->data);
+    }
+}
diff --git a/ld/sysdep.h b/ld/sysdep.h
index 3601a59a6ac..7d25e83ef53 100644
--- a/ld/sysdep.h
+++ b/ld/sysdep.h
@@ -41,6 +41,8 @@ 
 #include <unistd.h>
 #endif
 
+#include <errno.h>
+
 #ifdef HAVE_REALPATH
 # define REALPATH(a,b) realpath (a, b)
 #else