C++ 함수 인자로 unaligned 포인터를 어떻게 받아야 할까요?
글쓴이: pro0331 / 작성시간: 월, 2015/10/19 - 8:51오후
void foo(int *a); struct A { char c; int i; } __attribute__((__packed__)); int main() { A a; foo(&a.i); }
이런식의 코드가 있다고 할 때, foo()에서 align 안 된 int 포인터를 안전하게 처리할 수 있는 방법이 뭐가 있을까요?
인터넷을 검색하다보니 foo(__packed int *a) 이런 식으로 선언하면 된다는 글도 있던데, 제 환경에서는 컴파일이 안되네요. ㅠㅠ
Forums:
지역 int 포인터변수 하나 선언해두고
지역 int 포인터변수 하나 선언해두고 memcpy()로 복사한 다음 쓰시면 됩니다.
Written By the Black Knight of Destruction
그렇게 해 봐도 최적화 옵션을 주면 memcpy를
그렇게 해 봐도 최적화 옵션을 주면 memcpy를 생략하고 그냥 대입을 해버리네요..
함수 인자를 void*로 받아서 int에 복사하는건 동작은 하는데, 혹시 좀 더 깔끔한 방법이 없을까 해서요.
그렇다면 인라인 어셈블리 쓰셔야 할겁니다.
그렇다면 인라인 어셈블리 쓰셔야 할겁니다.
아 앞에서 얘기 잘못했네요. int 포인터변수가 아니라 alignment 안맞는 변수에서 값을 가져와서 임시로 저장할 int 지역변수를 만든 다음 memcpy()에 그 int 변수 주소를 인자로 넣으라는 얘기였습니다.
Written By the Black Knight of Destruction
제가 뭔가 헷갈리는 것 같은데..."안전하게
제가 뭔가 헷갈리는 것 같은데..."안전하게 처리"라는 말이 제가 생각하는 그 뜻이 맞는지 모르겠습니다.
address alignment를 지켜야하는 상황이라면 주소를 바꾸거나 접근 방식을 바꿔야 하는데,
0x01 address 에 있는 int value를 읽으려면 별 수 없이 0x01 을 접근하는 수 밖에 없으니,
결국은 접근 방식을 바꿔야하겠는데,
새로운 포인터 변수에 대입을 하건 memcpy를 하건 그릇만 달라질 뿐 알맹이는 여전히 0x01 일 테니 별 소용이 없겠고요.
gcc 의 경우엔 http://lxr.free-electrons.com/source/include/linux/unaligned/ 처럼 벌려놓고,
http://lxr.free-electrons.com/ident?i=get_unaligned 처럼 사용할 수 있습니다.
감사합니다!
HAVE_EFFICIENT_UNALIGNED_ACCESS는 사용할 수 없는 상황인 것 같아서, linux/unaligned/packed_struct.h 와 유사한 형태로 해결했습니다.
지역변수로 memcpy() 하라는 것은 보통
지역변수로 memcpy() 하라는 것은 보통 지역변수들은 address alignment가 되어 있기 때문에 지역변수에 byte 단위로 복사해 넣은 다음에 지역변수를 쓰면 address alignment 신경 안써도 되기 때문입니다. 그리고 지역변수에서 작업 다 끝나면 packed 된 곳에 다시 memcpy() 해야죠.
packed를 unpacked로 벌려놓는것도 결국에는 구조체의 각 멤버에 대해 이 작업을 반복해서 alignment를 맞춘 새로운 구조체를 만드는거고.
x86이라면 address alignment 안맞아도 하드웨어에서 보정해줘서(대신 메모리 접근이 2번 일어나기 때문에 그에 따른 패널티가 있습니다) 신경 안써도 되는데 pa-risc나 power, arm까지 쓰겠다면 이작업 안하면 bus error 내면서 뻗습니다.
Written By the Black Knight of Destruction
ARM EABI 가 보편화 되던 와중에... arm
ARM EABI 가 보편화 되던 와중에...
arm linux 커널의 alignment trap 에서 fixup 옵션을 꺼놓고 한동안 즐겁게 지내던 와중에 느닷없이 당한적이 있는데,
지역 변수를 이용해서 ioctl syscall 을 하는 부분이었고, 살펴보니 그 지역 변수는 스택 상에서 align 이 맞춰지지 않았었고요.
오히려 EABI gcc 이기때문에 긴장을 해야하는 부분도 있다는 걸 깨닫게 됐죠.
구조체 unpacked 에 대한 말씀은 제가 잘 모르겠습니다.
메모리 접근이 두 번 일어나는 것은,
cpu 와 ram 사이의 address bus width 에 들어맞지 않는 모든 access 가 그런 식으로 쪼개질 수 밖에 없으니 좀 다른 얘기라 생각합니다.
상대적으로 보면 비용이 비싼 것은 사실이지만, DDR 의 특성을 생각하면 그걸 '두 번'이라 부를 수 있을 지는 더 공부해봐야 알겠네요.
댓글 달기