|
Message-ID: <CAJ86T=U78hTsF_4dr_iYe3hyEjBwOTQbfd2Cw+kxLmTwb1cgfQ@mail.gmail.com> Date: Tue, 1 May 2018 14:49:00 -0700 From: Andre McCurdy <armccurdy@...il.com> To: musl@...ts.openwall.com Cc: Patrick Oppenlander <patrick.oppenlander@...il.com> Subject: Re: Some questions On Tue, May 1, 2018 at 10:35 AM, Rich Felker <dalias@...c.org> wrote: > On Tue, May 01, 2018 at 11:52:33AM -0400, Rich Felker wrote: >> On Tue, May 01, 2018 at 12:34:13PM +1000, Patrick Oppenlander wrote: >> > On Tue, May 1, 2018 at 1:31 AM, Rich Felker <dalias@...c.org> wrote: >> > > On Mon, Apr 30, 2018 at 03:29:39PM +1000, Patrick Oppenlander wrote: >> > >> Actually, my biggest issue with getcwd is that it allocates a PATH_MAX >> > >> sized buffer on the stack. That's painful on deeply embedded stuff. >> > > >> > > That's unrelated, and could/should be fixed by the attached patch I >> > > think. >> > >> > Unfortunately that fails to build on arm with: >> > >> > src/unistd/getcwd.c: In function 'getcwd': >> > src/unistd/getcwd.c:25:1: error: r7 cannot be used in asm here >> >> Then that's a bug we need to fix or work around elsewhere. >> Non-arch-specific source files can't be constrained not to use >> perfectly valid C constructs because gcc breaks on them for particular >> archs. >> >> I believe it's related to the thumb+framepointer issue that was raised >> a while back, but I forget how that ended and if we ever solved it. >> >> > I was also having a go at resolving the stack & the buffer size issue >> > and came up with the attached (untested) patch. >> > >> > Patrick >> >> > diff --git a/src/unistd/getcwd.c b/src/unistd/getcwd.c >> > index 103fbbb5..306dbc4f 100644 >> > --- a/src/unistd/getcwd.c >> > +++ b/src/unistd/getcwd.c >> > @@ -3,17 +3,10 @@ >> > #include <limits.h> >> > #include <string.h> >> > #include "syscall.h" >> > +#include "libc.h" >> > >> > -char *getcwd(char *buf, size_t size) >> > +static char *do_getcwd(char *buf, size_t size) >> > { >> > - char tmp[PATH_MAX]; >> > - if (!buf) { >> > - buf = tmp; >> > - size = PATH_MAX; >> > - } else if (!size) { >> > - errno = EINVAL; >> > - return 0; >> > - } >> > long ret = syscall(SYS_getcwd, buf, size); >> > if (ret < 0) >> > return 0; >> > @@ -21,5 +14,37 @@ char *getcwd(char *buf, size_t size) >> > errno = ENOENT; >> > return 0; >> > } >> > - return buf == tmp ? strdup(buf) : buf; >> > + return buf; >> > +} >> > + >> > +static char *getcwd_glibc(size_t size) >> > +{ >> > + char tmp[PATH_MAX]; >> > + if (!do_getcwd(tmp, sizeof tmp)) >> > + return 0; >> > + size_t len = strlen(tmp) + 1; >> > + if (!size) >> > + size = len; >> > + else if (size < len) { >> > + errno = ERANGE; >> > + return 0; >> > + } >> > + char *buf = malloc(size); >> > + if (!buf) { >> > + errno = ENOMEM; >> > + return 0; >> > + } >> > + memcpy(buf, tmp, len); >> > + return buf; >> > +} >> > + >> > +char *getcwd(char *buf, size_t size) >> > +{ >> > + if (!buf) >> > + return getcwd_glibc(size); >> > + if (!size) { >> > + errno = EINVAL; >> > + return 0; >> > + } >> > + return do_getcwd(buf, size); >> > } >> >> This isn't acceptable. It makes the code much larger (at the source >> level) and harder to read, and the only reason it works is failure of >> gcc to optimize heavily. It could just as easily still end up using >> the full PATH_MAX space on the stack, if gcc inlines and hoists stuff, >> or if gcc wanted to be really awful it could still end up using a >> frame pointer. >> >> Let's look back at the framepointer mess and see if there's a way to >> get gcc not to break. If not we may need to skip inline syscalls and >> call out to the extern __syscall when building for thumb, but I'd >> really rather not have to do that. > > Looking back, it seems where we left it is just that you need to make > sure frame pointer is disabled if building as thumb. But that's not > reliable because gcc forcibly re-enables frame pointer (including > frame pointer ABI constraints, which it doesn't need to) if you use a > VLA or alloca. > > I'm considering applying the attached patch, which would make it so > VLAs don't break thumb syscalls and eliminate the need to force frame > pointer off when building as thumb. This is all a workaround for gcc > being wrong about not letting you use r7, but it seems reasonable and > non-invasive. It just omits r7 from the constraints and uses a temp > register to save/restore it. This seems to fail when compiling src/thread/arm/__set_thread_area.c: {standard input}: Assembler messages: {standard input}:45: Error: invalid constant (f0005) after fixup make: *** [obj/src/thread/arm/__set_thread_area.o] Error 1 Without the patch, __set_thread_area() effectively compiles to: __set_thread_area: push {r7, lr} ldr r7, .L2 pop {r7, pc} .L2: .word 983045 With the patch: __set_thread_area: push {r7, lr} add r7, sp, #0 mov r3,r7 ; mov r7,#983045 ; svc 0 ; mov r7,r3 pop {r7, pc} ie the immediate value 0xf0005 can't be loaded directly into r7 with a single Thumb2 mov instruction. I tried a quick test to replace the single mov instruction in __asm_syscall() with a movw + movt pair: #define __asm_syscall(...) do { \ __asm__ __volatile__ ( "mov %1,r7 ; movw r7,%2 & 0xffff ; movt r7,%2 >> 16 ; svc 0 ; mov r7,%1" \ : "=r"(r0), "=&r"((int){0}) : __VA_ARGS__ : "memory"); \ return r0; \ } while (0) It fixes __set_thread_area() but causes a new error in syscall() as the syscall number is passed to __asm_syscall() as a variable rather than an immediate: {standard input}: Assembler messages: {standard input}:75: Error: constant expression expected -- `movw r7,r6&0xffff' {standard input}:75: Error: constant expression expected -- `movt r7,r6>>16' make: *** [obj/src/misc/syscall.o] Error 1
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.