How can I align a string literal to an address whi

2019-07-29 02:28发布

问题:

I'd like to ensure that a given string literal ends up at an address that is a multiple of 2, or even better, 4.

Is there any way to achieve that, preferably without using any compiler-specific extensions? Or is it impossible?

I'd like to do this so the lowermost bits of the string address are 0 and can be (ab)used as tag bits.

回答1:

In C99 you can do this using a union, for example

#define ALIGNED_STR_UNION(N, S) const union { char s[sizeof S]; int align; } N = { S }
ALIGNED_STR_UNION(sssu, "XYZABC");

Adjust the type int as necessary.

With that, sssu.s refers to the characters.

The .s can be avoided like

#define ALIGNED_STR(S) ((const union { char s[sizeof S]; int align; }){ S }.s)
const char *sss = ALIGNED_STR("XYZABC");

However, this version wastes space on the pointer (including a relative relocation for position independent code) and does not allow declaring static literals in functions.

It is probably better to use the non-standard alignment attributes instead of this.



回答2:

You can do this using C11 (but not C99). For statically allocated buffers you can use alignas to do this:

#include <stdio.h>
#include <stdalign.h>

alignas(4) char str[] = "this is aligned to at least 4 bytes";

int main() {
  char a;
  alignas(4) char str2[] = "and again";
  printf("%p\n", &a);
  printf("%p\n", str);
  printf("%p\n", str2);
}

The trick above is that the string literal is actually being use to initialize a char array of the same size, which lets you use alignas in the type.

For dynamically allocated ones you use aligned_alloc(size_t alignment, size_t size) instead of malloc.

There are other older non-standard ways of doing this which work with GCC/Clang/Intel compilers going back quite some way too, so if you don't have C11 available always you can dress this up with some extra pre-processor work, e.g.:

#if __STDC_VERSION__ >= 201112L
# include <stdalign.h>
# define force_align(x) alignas(x)
#elif defined __GNUC__
# define force_align(x) __attribute__((aligned(x)))
#elif defined __MSC_VER
# define force_align(x) __declspec(align(x))
#else
# error Who are you?
#endif

force_align(128) int x; // Note: maybe your linker doesn't actually support 128 anyway!

Which favours the C11 solution, but uses a GCC specific extension or MSVC one where nothing else suitable exists.