[CFR] mge driver / elf reloc

Bruce Evans brde at optusnet.com.au
Mon Jul 21 19:55:35 UTC 2014


On Tue, 22 Jul 2014, Bruce Evans wrote:

> ...
> This behaviour can probable be exploited in the enc/dec functions.
> When there is no endianness conversion, write 32-bit accesses as
> p->x where p is a pointer to a __packed __aligned(1) struct containing
> x.  The compiler will then produce the above mess on ia64 and a single
> 32-bit access if possible.  No ifdefs required.  When there is an
> endianess conversion, do it on a register with value p->x.
>
> Lightly tested implementation:
>
> % struct _le32 {
> % 	uint32_t _x;
> % } __packed;
> % % #define	le32enc(p, u)	(((struct _le32 *)(p))->_x = (u))
>
> This is simpler than the inline version, and fixes some namespace errors.

Oops, that is not so good.  I just rememembed another optimization that
at least clang does in at least some cases for the inline version: if
the the compiler can see that the pointer is to aligned memory (which it
can sometimes do since the function is inline), then the compiler generates
1 32-bit access.  The __packed attribute in the above defeats this by
forcing to 1-byte alignment.

> If you want avoid the mess on ia64, this can be done at compile time if
> the alignment is known to be more than 1 then.  I think if can often
> be known, as for struct ip (don't generate misaligned struct ip, and
> if you start with one then copy to an aligned one).  The enc/dec
> inline functions could handle this by being converted to macros that
> take the alignment parameter.  If the alignment is not known until
> runtime...don't do that.
>
> To add an alignment parameter to the above, use something like:
>
> #define	_sle32(a)	struct _le32 { uint32_t _x; } __packed __aligned(a)
> #define	le32enc(p, u, a)	(((_sle32(a) *)(p))->_x = (u))
>
> Macroizing the struct declaration to add the alignment parameter to it
> and avoiding backslashes made the code less readable but even shorter.
>
> This was tested on i386 and ia64 with alignments 1 and 4 and and gave
> the expected output in asm.

Also not so good.  If the pointer was 'a'-byte aligned, then the 'a'
parameter recovers by tells the compiler this in a worse way after
__packed clobbers the original alignment.  It is better for the caller
to do any alignment.

In other replies, we discussed using memcpy() to force alignment.  The
above macros could use it to copy to aligned memory and load as if
from that memory less hackishly.  This would work in the inline
functions, but doesn't do a lot that the compiler can't already do.
It is still better for callers to do any alignment.  They can use
memcpy(), or if they know that the pointer is n-byte aligned then they
can cast the pointer an __aligned(n) one where the inline fnction
can see the cast.  The original pointer type might be void * or char *
so memcpy() for alignment would have to copy memory, but _aligned(n)
would be virtual.

Bruce


More information about the freebsd-arm mailing list