Home | History | Annotate | Download | only in libasm
      1 /* Align section.
      2    Copyright (C) 2002 Red Hat, Inc.
      3    Written by Ulrich Drepper <drepper (at) redhat.com>, 2002.
      4 
      5    This program is Open Source software; you can redistribute it and/or
      6    modify it under the terms of the Open Software License version 1.0 as
      7    published by the Open Source Initiative.
      8 
      9    You should have received a copy of the Open Software License along
     10    with this program; if not, you may obtain a copy of the Open Software
     11    License version 1.0 from http://www.opensource.org/licenses/osl.php or
     12    by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
     13    3001 King Ranch Road, Ukiah, CA 95482.   */
     14 
     15 #ifdef HAVE_CONFIG_H
     16 # include <config.h>
     17 #endif
     18 
     19 #include <stdlib.h>
     20 #include <sys/param.h>
     21 
     22 #include <libasmP.h>
     23 #include <system.h>
     24 
     25 
     26 int
     27 asm_align (asmscn, value)
     28      AsmScn_t *asmscn;
     29      GElf_Word value;
     30 {
     31   if (asmscn == NULL)
     32     /* An earlier error.  */
     33     return -1;
     34 
     35       /* The alignment value must be a power of two.  */
     36   if (unlikely (! powerof2 (value)))
     37     {
     38       __libasm_seterrno (ASM_E_INVALID);
     39       return -1;
     40     }
     41 
     42   rwlock_wrlock (asmscn->ctx->lock);
     43 
     44   int result = 0;
     45 
     46   /* Fillbytes necessary?  */
     47   if ((asmscn->offset & (value - 1)) != 0)
     48     {
     49       /* Add fillbytes.  */
     50       size_t cnt;
     51       size_t byteptr;
     52 
     53       cnt = value - (asmscn->offset & (value - 1));
     54 
     55       /* Ensure there is enough room to add the fill bytes.  */
     56       result = __libasm_ensure_section_space (asmscn, cnt);
     57       if (result != 0)
     58 	goto out;
     59 
     60       /* Fill in the bytes.  We align the pattern according to the
     61 	 current offset.  */
     62       byteptr = asmscn->offset % asmscn->pattern->len;
     63 
     64       /* Update the total size.  */
     65       asmscn->offset += cnt;
     66 
     67       do
     68 	{
     69 	  asmscn->content->data[asmscn->content->len++]
     70 	    = asmscn->pattern->bytes[byteptr++];
     71 
     72 	  if (byteptr == asmscn->pattern->len)
     73 	    byteptr = 0;
     74 	}
     75       while (--cnt > 0);
     76     }
     77 
     78   /* Remember the maximum alignment for this subsection.  */
     79   if (asmscn->max_align < value)
     80     {
     81       asmscn->max_align = value;
     82 
     83       /* Update the parent as well (if it exists).  */
     84       if (asmscn->subsection_id != 0)
     85 	{
     86 	  rwlock_wrlock (asmscn->data.up->ctx->lock);
     87 
     88 	  if (asmscn->data.up->max_align < value)
     89 	    asmscn->data.up->max_align = value;
     90 
     91 	  rwlock_unlock (asmscn->data.up->ctx->lock);
     92 	}
     93     }
     94 
     95  out:
     96   rwlock_unlock (asmscn->ctx->lock);
     97 
     98   return result;
     99 }
    100 
    101 
    102 /* Ensure there are at least LEN bytes available in the output buffer
    103    for ASMSCN.  */
    104 int
    105 __libasm_ensure_section_space (asmscn, len)
    106      AsmScn_t *asmscn;
    107      size_t len;
    108 {
    109   /* The blocks with the section content are kept in a circular
    110      single-linked list.  */
    111   size_t size;
    112 
    113   if (asmscn->content == NULL)
    114     {
    115       /* This is the first block.  */
    116       size = MAX (2 * len, 960);
    117 
    118       asmscn->content = (struct AsmData *) malloc (sizeof (struct AsmData)
    119 						   + size);
    120       if (asmscn->content == NULL)
    121 	return -1;
    122 
    123       asmscn->content->next = asmscn->content;
    124     }
    125   else
    126     {
    127       struct AsmData *newp;
    128 
    129       if (asmscn->content->maxlen - asmscn->content->len >= len)
    130 	/* Nothing to do, there is enough space.  */
    131 	return 0;
    132 
    133       size = MAX (2 *len, MIN (32768, 2 * asmscn->offset));
    134 
    135       newp = (struct AsmData *) malloc (sizeof (struct AsmData) + size);
    136       if (newp == NULL)
    137 	return -1;
    138 
    139       newp->next = asmscn->content->next;
    140       asmscn->content = asmscn->content->next = newp;
    141     }
    142 
    143   asmscn->content->len = 0;
    144   asmscn->content->maxlen = size;
    145 
    146   return 0;
    147 }
    148