1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
3 * ARM specific definitions for NOLIBC
7 #ifndef _NOLIBC_ARCH_ARM_H
8 #define _NOLIBC_ARCH_ARM_H
12 /* The struct returned by the stat() syscall, 32-bit only, the syscall returns
13 * exactly 56 bytes (stops before the unused array). In big endian, the format
14 * differs as devices are returned as short only.
16 struct sys_stat_struct {
17 #if defined(__ARMEB__)
18 unsigned short st_dev;
19 unsigned short __pad1;
24 unsigned short st_mode;
25 unsigned short st_nlink;
26 unsigned short st_uid;
27 unsigned short st_gid;
29 #if defined(__ARMEB__)
30 unsigned short st_rdev;
31 unsigned short __pad2;
33 unsigned long st_rdev;
35 unsigned long st_size;
36 unsigned long st_blksize;
37 unsigned long st_blocks;
39 unsigned long st_atime;
40 unsigned long st_atime_nsec;
41 unsigned long st_mtime;
42 unsigned long st_mtime_nsec;
44 unsigned long st_ctime;
45 unsigned long st_ctime_nsec;
46 unsigned long __unused[2];
49 /* Syscalls for ARM in ARM or Thumb modes :
50 * - registers are 32-bit
51 * - stack is 8-byte aligned
52 * ( http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka4127.html)
53 * - syscall number is passed in r7
54 * - arguments are in r0, r1, r2, r3, r4, r5
55 * - the system call is performed by calling svc #0
56 * - syscall return comes in r0.
57 * - only lr is clobbered.
58 * - the arguments are cast to long and assigned into the target registers
59 * which are then simply passed as registers to the asm code, so that we
60 * don't have to experience issues with register constraints.
61 * - the syscall number is always specified last in order to allow to force
62 * some registers before (gcc refuses a %-register at the last position).
63 * - in thumb mode without -fomit-frame-pointer, r7 is also used to store the
64 * frame pointer, and we cannot directly assign it as a register variable,
65 * nor can we clobber it. Instead we assign the r6 register and swap it
66 * with r7 before calling svc, and r6 is marked as clobbered.
67 * We're just using any regular register which we assign to r7 after saving
70 * Also, ARM supports the old_select syscall if newselect is not available
72 #define __ARCH_WANT_SYS_OLD_SELECT
74 #if (defined(__THUMBEB__) || defined(__THUMBEL__)) && \
75 !defined(NOLIBC_OMIT_FRAME_POINTER)
76 /* swap r6,r7 needed in Thumb mode since we can't use nor clobber r7 */
77 #define _NOLIBC_SYSCALL_REG "r6"
78 #define _NOLIBC_THUMB_SET_R7 "eor r7, r6\neor r6, r7\neor r7, r6\n"
79 #define _NOLIBC_THUMB_RESTORE_R7 "mov r7, r6\n"
81 #else /* we're in ARM mode */
82 /* in Arm mode we can directly use r7 */
83 #define _NOLIBC_SYSCALL_REG "r7"
84 #define _NOLIBC_THUMB_SET_R7 ""
85 #define _NOLIBC_THUMB_RESTORE_R7 ""
87 #endif /* end THUMB */
89 #define my_syscall0(num) \
91 register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \
92 register long _arg1 __asm__ ("r0"); \
95 _NOLIBC_THUMB_SET_R7 \
97 _NOLIBC_THUMB_RESTORE_R7 \
98 : "=r"(_arg1), "=r"(_num) \
101 : "memory", "cc", "lr" \
106 #define my_syscall1(num, arg1) \
108 register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \
109 register long _arg1 __asm__ ("r0") = (long)(arg1); \
112 _NOLIBC_THUMB_SET_R7 \
114 _NOLIBC_THUMB_RESTORE_R7 \
115 : "=r"(_arg1), "=r" (_num) \
118 : "memory", "cc", "lr" \
123 #define my_syscall2(num, arg1, arg2) \
125 register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \
126 register long _arg1 __asm__ ("r0") = (long)(arg1); \
127 register long _arg2 __asm__ ("r1") = (long)(arg2); \
130 _NOLIBC_THUMB_SET_R7 \
132 _NOLIBC_THUMB_RESTORE_R7 \
133 : "=r"(_arg1), "=r" (_num) \
134 : "r"(_arg1), "r"(_arg2), \
136 : "memory", "cc", "lr" \
141 #define my_syscall3(num, arg1, arg2, arg3) \
143 register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \
144 register long _arg1 __asm__ ("r0") = (long)(arg1); \
145 register long _arg2 __asm__ ("r1") = (long)(arg2); \
146 register long _arg3 __asm__ ("r2") = (long)(arg3); \
149 _NOLIBC_THUMB_SET_R7 \
151 _NOLIBC_THUMB_RESTORE_R7 \
152 : "=r"(_arg1), "=r" (_num) \
153 : "r"(_arg1), "r"(_arg2), "r"(_arg3), \
155 : "memory", "cc", "lr" \
160 #define my_syscall4(num, arg1, arg2, arg3, arg4) \
162 register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \
163 register long _arg1 __asm__ ("r0") = (long)(arg1); \
164 register long _arg2 __asm__ ("r1") = (long)(arg2); \
165 register long _arg3 __asm__ ("r2") = (long)(arg3); \
166 register long _arg4 __asm__ ("r3") = (long)(arg4); \
169 _NOLIBC_THUMB_SET_R7 \
171 _NOLIBC_THUMB_RESTORE_R7 \
172 : "=r"(_arg1), "=r" (_num) \
173 : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \
175 : "memory", "cc", "lr" \
180 #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
182 register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \
183 register long _arg1 __asm__ ("r0") = (long)(arg1); \
184 register long _arg2 __asm__ ("r1") = (long)(arg2); \
185 register long _arg3 __asm__ ("r2") = (long)(arg3); \
186 register long _arg4 __asm__ ("r3") = (long)(arg4); \
187 register long _arg5 __asm__ ("r4") = (long)(arg5); \
190 _NOLIBC_THUMB_SET_R7 \
192 _NOLIBC_THUMB_RESTORE_R7 \
193 : "=r"(_arg1), "=r" (_num) \
194 : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
196 : "memory", "cc", "lr" \
201 #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
203 register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \
204 register long _arg1 __asm__ ("r0") = (long)(arg1); \
205 register long _arg2 __asm__ ("r1") = (long)(arg2); \
206 register long _arg3 __asm__ ("r2") = (long)(arg3); \
207 register long _arg4 __asm__ ("r3") = (long)(arg4); \
208 register long _arg5 __asm__ ("r4") = (long)(arg5); \
209 register long _arg6 __asm__ ("r5") = (long)(arg6); \
212 _NOLIBC_THUMB_SET_R7 \
214 _NOLIBC_THUMB_RESTORE_R7 \
215 : "=r"(_arg1), "=r" (_num) \
216 : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
217 "r"(_arg6), "r"(_num) \
218 : "memory", "cc", "lr" \
224 char **environ __attribute__((weak));
225 const unsigned long *_auxv __attribute__((weak));
228 void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
231 #ifdef _NOLIBC_STACKPROTECTOR
232 "bl __stack_chk_init\n" /* initialize stack protector */
234 "pop {%r0}\n" /* argc was in the stack */
235 "mov %r1, %sp\n" /* argv = sp */
237 "add %r2, %r0, $1\n" /* envp = (argc + 1) ... */
238 "lsl %r2, %r2, $2\n" /* * 4 ... */
239 "add %r2, %r2, %r1\n" /* + argv */
240 "ldr %r3, 1f\n" /* r3 = &environ (see below) */
241 "str %r2, [r3]\n" /* store envp into environ */
243 "mov r4, r2\n" /* search for auxv (follows NULL after last env) */
245 "mov r5, r4\n" /* r5 = r4 */
246 "add r4, r4, #4\n" /* r4 += 4 */
247 "ldr r5,[r5]\n" /* r5 = *r5 = *(r4-4) */
248 "cmp r5, #0\n" /* and stop at NULL after last env */
250 "ldr %r3, 2f\n" /* r3 = &_auxv (low bits) */
251 "str r4, [r3]\n" /* store r4 into _auxv */
253 "mov %r3, $8\n" /* AAPCS : sp must be 8-byte aligned in the */
254 "neg %r3, %r3\n" /* callee, and bl doesn't push (lr=pc) */
255 "and %r3, %r3, %r1\n" /* so we do sp = r1(=sp) & r3(=-8); */
258 "bl main\n" /* main() returns the status code, we'll exit with it. */
259 "movs r7, $1\n" /* NR_exit == 1 */
261 ".align 2\n" /* below are the pointers to a few variables */
267 __builtin_unreachable();
270 #endif /* _NOLIBC_ARCH_ARM_H */