blob: a7e2f47ffc9bb7f896b0541c702f5f908be43b33 [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/* vi: set sw=4 ts=4: */
2/*
3 * Copyright (C) 2000-2005 by Erik Andersen <andersen@codepoet.org>
4 *
5 * GNU Lesser General Public License version 2.1 or later.
6 */
7
8#ifndef _LINUX_STRING_H_
9#define _LINUX_STRING_H_
10
11#include <dl-sysdep.h> /* for do_rem */
12#include <features.h>
13
14/* provide some sane defaults */
15#ifndef do_rem
16# define do_rem(result, n, base) ((result) = (n) % (base))
17#endif
18#ifndef do_div_10
19# define do_div_10(result, remain) ((result) /= 10)
20#endif
21
22static size_t _dl_strlen(const char *str);
23static char *_dl_strcat(char *dst, const char *src);
24static char *_dl_strcpy(char *dst, const char *src);
25static int _dl_strcmp(const char *s1, const char *s2);
26static int _dl_strncmp(const char *s1, const char *s2, size_t len);
27static char *_dl_strchr(const char *str, int c);
28static char *_dl_strrchr(const char *str, int c);
29static char *_dl_strstr(const char *s1, const char *s2);
30static void *_dl_memcpy(void *dst, const void *src, size_t len);
31static int _dl_memcmp(const void *s1, const void *s2, size_t len);
32static void *_dl_memset(void *str, int c, size_t len);
33static char *_dl_get_last_path_component(char *path);
34static char *_dl_simple_ltoa(char *local, unsigned long i);
35static char *_dl_simple_ltoahex(char *local, unsigned long i);
36
37#ifndef NULL
38#define NULL ((void *) 0)
39#endif
40
41static __always_inline size_t _dl_strlen(const char *str)
42{
43 register const char *ptr = (char *) str-1;
44 while (*++ptr)
45 ;/* empty */
46 return (ptr - str);
47}
48
49static __always_inline char * _dl_strcat(char *dst, const char *src)
50{
51 register char *ptr = dst-1;
52
53 src--;
54 while (*++ptr)
55 ;/* empty */
56 ptr--;
57 while ((*++ptr = *++src) != 0)
58 ;/* empty */
59 return dst;
60}
61
62static __always_inline char * _dl_strcpy(char *dst, const char *src)
63{
64 register char *ptr = dst;
65
66 dst--;src--;
67 while ((*++dst = *++src) != 0)
68 ;/* empty */
69
70 return ptr;
71}
72
73static __always_inline int _dl_strcmp(const char *s1, const char *s2)
74{
75 register unsigned char c1, c2;
76 s1--;s2--;
77 do {
78 c1 = (unsigned char) *++s1;
79 c2 = (unsigned char) *++s2;
80 if (c1 == '\0')
81 return c1 - c2;
82 } while (c1 == c2);
83
84 return c1 - c2;
85}
86
87static __always_inline int _dl_strncmp(const char *s1, const char *s2, size_t len)
88{
89 register unsigned char c1 = '\0';
90 register unsigned char c2 = '\0';
91
92 s1--;s2--;
93 while (len > 0) {
94 c1 = (unsigned char) *++s1;
95 c2 = (unsigned char) *++s2;
96 if (c1 == '\0' || c1 != c2)
97 return c1 - c2;
98 len--;
99 }
100 return c1 - c2;
101}
102
103static __always_inline char * _dl_strchr(const char *str, int c)
104{
105 register char ch;
106 str--;
107 do {
108 if ((ch = *++str) == c)
109 return (char *) str;
110 }
111 while (ch);
112
113 return 0;
114}
115
116static __always_inline char * _dl_strrchr(const char *str, int c)
117{
118 register char *prev = 0;
119 register char *ptr = (char *) str-1;
120
121 while (*++ptr != '\0') {
122 if (*ptr == c)
123 prev = ptr;
124 }
125 if (c == '\0')
126 return(ptr);
127 return(prev);
128}
129
130static __always_inline char * _dl_strstr(const char *s1, const char *s2)
131{
132 register const char *s = s1;
133 register const char *p = s2;
134
135 do {
136 if (!*p)
137 return (char *) s1;;
138 if (*p == *s) {
139 ++p;
140 ++s;
141 } else {
142 p = s2;
143 if (!*s)
144 return NULL;
145 s = ++s1;
146 }
147 } while (1);
148}
149
150static __always_inline void * _dl_memcpy(void *dst, const void *src, size_t len)
151{
152 register char *a = dst-1;
153 register const char *b = src-1;
154
155 while (len) {
156 *++a = *++b;
157 --len;
158 }
159 return dst;
160}
161
162static __always_inline int _dl_memcmp(const void *s1, const void *s2, size_t len)
163{
164 unsigned char *c1 = (unsigned char *)s1-1;
165 unsigned char *c2 = (unsigned char *)s2-1;
166
167 while (len) {
168 if (*++c1 != *++c2)
169 return *c1 - *c2;
170 len--;
171 }
172 return 0;
173}
174
175#if defined(powerpc)
176/* Will generate smaller and faster code due to loop unrolling.*/
177static __always_inline void * _dl_memset(void *to, int c, size_t n)
178{
179 unsigned long chunks;
180 unsigned long *tmp_to;
181 unsigned char *tmp_char;
182
183 chunks = n / 4;
184 tmp_to = to + n;
185 c = c << 8 | c;
186 c = c << 16 | c;
187 if (!chunks)
188 goto lessthan4;
189 do {
190 *--tmp_to = c;
191 } while (--chunks);
192lessthan4:
193 n = n % 4;
194 if (!n)
195 return to;
196 tmp_char = (unsigned char *)tmp_to;
197 do {
198 *--tmp_char = c;
199 } while (--n);
200 return to;
201}
202#else
203static __always_inline void * _dl_memset(void *str, int c, size_t len)
204{
205 register char *a = str;
206
207 while (len--)
208 *a++ = c;
209
210 return str;
211}
212#endif
213
214static __always_inline char * _dl_get_last_path_component(char *path)
215{
216 register char *ptr = path-1;
217
218 while (*++ptr)
219 ;/* empty */
220
221 /* strip trailing slashes */
222 while (ptr != path && *--ptr == '/') {
223 *ptr = '\0';
224 }
225
226 /* find last component */
227 while (ptr != path && *--ptr != '/')
228 ;/* empty */
229 return ptr == path ? ptr : ptr+1;
230}
231
232/* Early on, we can't call printf, so use this to print out
233 * numbers using the SEND_STDERR() macro. Avoid using mod
234 * or using long division */
235static __always_inline char * _dl_simple_ltoa(char *local, unsigned long i)
236{
237 /* 20 digits plus a null terminator should be good for
238 * 64-bit or smaller ints (2^64 - 1)*/
239 char *p = &local[22];
240 *--p = '\0';
241 do {
242 char temp;
243 do_rem(temp, i, 10);
244 *--p = '0' + temp;
245 do_div_10(i, temp);
246 } while (i > 0);
247 return p;
248}
249
250static __always_inline char * _dl_simple_ltoahex(char *local, unsigned long i)
251{
252 /* 16 digits plus a leading "0x" plus a null terminator,
253 * should be good for 64-bit or smaller ints */
254 char *p = &local[22];
255 *--p = '\0';
256 do {
257 char temp = i & 0xf;
258 if (temp <= 0x09)
259 *--p = '0' + temp;
260 else
261 *--p = 'a' - 0x0a + temp;
262 i >>= 4;
263 } while (i > 0);
264 *--p = 'x';
265 *--p = '0';
266 return p;
267}
268
269
270
271
272/* The following macros may be used in dl-startup.c to debug
273 * ldso before ldso has fixed itself up to make function calls */
274
275/* On some (wierd) arches, none of this stuff works at all, so
276 * disable the whole lot... */
277#if defined(__mips__)
278
279# define SEND_STDERR(X)
280# define SEND_ADDRESS_STDERR(X, add_a_newline)
281# define SEND_NUMBER_STDERR(X, add_a_newline)
282
283#else
284
285/* On some arches constant strings are referenced through the GOT.
286 * This requires that load_addr must already be defined... */
287#if defined(mc68000) || defined(__arm__) || defined(__thumb__) || \
288 defined(__mips__) || defined(__sh__) || defined(__powerpc__) || \
289 defined(__avr32__) || defined(__xtensa__) || defined(__sparc__) || defined(__microblaze__)
290# define CONSTANT_STRING_GOT_FIXUP(X) \
291 if ((X) < (const char *) load_addr) (X) += load_addr
292# define NO_EARLY_SEND_STDERR
293#else
294# define CONSTANT_STRING_GOT_FIXUP(X)
295#endif
296
297#define SEND_STDERR(X) \
298{ \
299 const char *tmp1 = (X); \
300 CONSTANT_STRING_GOT_FIXUP(tmp1); \
301 _dl_write(2, tmp1, _dl_strlen(tmp1)); \
302}
303
304#define SEND_ADDRESS_STDERR(ADR, add_a_newline) \
305{ \
306 char tmp[26], v, *tmp2, *tmp1 = tmp; \
307 unsigned long X = (unsigned long)(ADR); \
308 CONSTANT_STRING_GOT_FIXUP(tmp1); \
309 tmp2 = tmp1 + sizeof(tmp); \
310 *--tmp2 = '\0'; \
311 if (add_a_newline) *--tmp2 = '\n'; \
312 do { \
313 v = (X) & 0xf; \
314 if (v <= 0x09) \
315 *--tmp2 = '0' + v; \
316 else \
317 *--tmp2 = 'a' - 0x0a + v; \
318 (X) >>= 4; \
319 } while ((X) > 0); \
320 *--tmp2 = 'x'; \
321 *--tmp2 = '0'; \
322 _dl_write(2, tmp2, tmp1 - tmp2 + sizeof(tmp) - 1); \
323}
324
325#define SEND_NUMBER_STDERR(NUM, add_a_newline) \
326{ \
327 char tmp[26], v, *tmp2, *tmp1 = tmp; \
328 unsigned long X = (unsigned long)(NUM); \
329 CONSTANT_STRING_GOT_FIXUP(tmp1); \
330 tmp2 = tmp1 + sizeof(tmp); \
331 *--tmp2 = '\0'; \
332 if (add_a_newline) *--tmp2 = '\n'; \
333 do { \
334 do_rem(v, (X), 10); \
335 *--tmp2 = '0' + v; \
336 do_div_10((X), v); \
337 } while ((X) > 0); \
338 _dl_write(2, tmp2, tmp1 - tmp2 + sizeof(tmp) - 1); \
339}
340#endif
341
342/* Some targets may have to override this to something that doesn't
343 * reference constant strings through the GOT. This macro should be
344 * preferred over SEND_STDERR for constant strings before we complete
345 * bootstrap.
346 */
347#ifndef SEND_EARLY_STDERR
348# define SEND_EARLY_STDERR(S) SEND_STDERR(S)
349#else
350# define EARLY_STDERR_SPECIAL
351#endif
352
353#ifdef __SUPPORT_LD_DEBUG_EARLY__
354# define SEND_STDERR_DEBUG(X) SEND_STDERR(X)
355# define SEND_EARLY_STDERR_DEBUG(X) SEND_EARLY_STDERR(X)
356# define SEND_NUMBER_STDERR_DEBUG(X, add_a_newline) SEND_NUMBER_STDERR(X, add_a_newline)
357# define SEND_ADDRESS_STDERR_DEBUG(X, add_a_newline) SEND_ADDRESS_STDERR(X, add_a_newline)
358#else
359# define SEND_STDERR_DEBUG(X)
360# define SEND_EARLY_STDERR_DEBUG(X)
361# define SEND_NUMBER_STDERR_DEBUG(X, add_a_newline)
362# define SEND_ADDRESS_STDERR_DEBUG(X, add_a_newline)
363#endif
364
365#endif