1 /* Align section.
2 Copyright (C) 2002 Red Hat, Inc.
3 Written by Ulrich Drepper <drepper@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
asm_align(asmscn,value)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
__libasm_ensure_section_space(asmscn,len)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