본문 바로가기

Etc

byte alignment






디스어셈블리를 하다 보면 알게 되는 '4바이트 정렬'

패킷을 다루다 보면 나는 분명히 구조체를 5바이트로 만들어서 쐈는데 받을 때에는 8바이트로 받는 일이 있다.

흔히 byte alignment 이라고 이야기한다. 최적화에 관련한 PPT 자료. 짧지만 뭐..



byte alignment.ppt




으레 #pragma pack(1) ... #pragma pack() 으로 alignment 를 풀어준다.

__packed 를 디파인으로 PACKED 라고 쓰기도 하고.

GCC 에서는 __attribute__((packed)) 라고도 쓴다. 혹 맞추고 싶은 alignment 가 있다면 __attribute__((align(4)))




걍 pragma pack 이 유지보수에도 가장 편한 방법.

아래는 1바이트 정렬에 대한 글





[1byte alignment 이야기]


작성: 이홍기 <orinmir _at_ chonga _dot_ pe _dot_ kr> http://chonga.pe.kr

작성일: 2001년 8월 2일


1. 개요


 온라인 게임이나 네트웍 프로그램을 작성하는 중에, 우리가 패킷단위를 structure로


정의해 memcpy등을 하려고 할 때, 기본 memory alignment 방식이 4byte(인텔 32bit기준)이므로 


실제로 structure 정의를 아래와 같이 하면


  struct pkt {

  int a;

  char b;

  };


분명 5byte만큼만 정의했지만, 기본 alignment는 4byte 씩이므로 sizeof는 8이 나온다.


memcpy를 해서 5byte 크기의 버퍼에다 넣어주면 밀려버린 상태로 들어가게 될 것이다. 


메모리의 효율적인 할당 방식으로 들어가는 것이 기본으로 설정되므로 우리가


원하는 결과를 얻기 힘들다.


이 때에는 1byte alignment를 해주어야하며, 기본 alignment가 아닌 경우 


전체적인 수행 속도에도 영향을 미친다는 이야기를 들은 적이 있긴하다..


하지만 어쩌랴.. 정확한 패킷 처리를 위해선 피하갈 수 없는 산이다.



그렇다면 alignment란 정녕 무엇인가? 궁금한 사람은 아래를 참조하고 


이도저도 귀찮은 사람은 사용방법으로 넘어가보자.


http://www.cs.umd.edu/class/fall1998/cmsc411/projects/outer/memory/align.htm



2. 사용방법



a) 전체에 걸기


   피치 못할 사정에 의해 컴파일할 때에 아예 전체를 1byte alignment를 해주어야 한다면 어떻게 

   해야할까?


   gcc를 예를 들면 -fpack-struct 쪽을 참고해주면 되겠다.

   (이 사이트 주목 http://gcc.gnu.org/ml/gcc/1999-03/msg00428.html)


위 사이트를 방문해 보면 알겠지만 아래와 같은 문제점이 있다고 한다.


     If the library and the rest of the application don't share *any*

     structures, it might work. This means that you can't do the following

     things in the library:

       - use stdio (e.g. printf)

       - use system calls that take structures (ioctl(2), stat(2))

       - use setjmp


   공유 라이브러리는 1byte alignment를 고려하지 않는 경우가 있기 때문에도 

   전체 scope으로 1byte alignment를 하면 굉장히 위험하다고 한다.


   또한 이유없이 SIGSEGV를 받고 죽어버릴 수도 있다.



b) #pragma pack 이용하여 범위 지정


   보통 1byte alignment를 하므로 


   #pragma pack(1)로 시작해주고 #pragma pack() 으로 끝내면서 기본값으로

   반환해준다.


   #pragma pack(4)이라고 끝내어도 되겠지만., 시스템이나 아키텍쳐마다


   다를 수 있으므로 pack()가 현실적이다. 


   예를 들자면


   #pragma pack(1)

   struct a { int i; char j; };

   struct b { char a[9]; unsigned short b; };    

   #pragma pack()

   struct c { char a[9]; unsigned short b; };    


   위는 sizeof(struct a)는 5이고, sizeof(struct b)는 11이다.

   하지만 sizeof(struct c)는 16이 나올 것이다.



c) __attribute__((packed)) 를 이용하여 개별적으로 지정


   각각의 structure나 class에 걸어줄 수가 있다.


   이 방법을 가장 추천한다.


   struct __attribute__((packed)) A {

    char c;

    int  i;

   } a ;


   struct B {

    char c;

    int  i;

   } b ;


   결과를 보자면 sizeof (a) 는 5이다.  sizeof (b) 는 8이다. 


**주의사항인데 아래와 같이 structure를 포함한 structure나 class에서


   class __attribute__((packed)) A {

   public:

   struct mystruct  {

   char c;

   int i;

   } st;

   public:

   A() { }

   ~A() { } 

   };


   위에서 mystruct는 4byte align이 된다. 실수하기 쉬운 부분이다.

아래와 같이 또 선언해줘야한다.


   class __attribute__((packed)) A {

   public:

   struct __attribute__((packed)) mystruct  {

   char c;

   int i;

   } st;

   public:

   A() { }

   ~A() { } 

   };


   또 한가지가 있는데 아래와 같이 소멸자에 virtual을 선언한 경우, vptr도

4byte(인텔 32bit 기준)을 먹는다. --;


   class __attribute__((packed)) A {

   public:

   struct __attribute__((packed)) mystruct  {

   char c;

   int i;

   public:

   A() { }

   virtual ~A() { } 

   };




3. 기타


  이 예제는 모두 gcc에서 테스트되었다.



'Etc' 카테고리의 다른 글

해커 선언문  (0) 2013.07.16