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