이 내용은 제가 기존에 만들었던 여러 소스(mzapi) 들을 64bit 에서 동작하도록 포팅하면서 발생했던 고려사항들을 정리합니다. (최신 내용은 https://bbs.minzkn.com/viewtopic.php?t=819 에서 확인할수 있습니다.


1. 변수형의 크기는 어떻게 달라지는가? 32bit 환경에서 64bit 환경으로 옮겨가면서 달라진 변수형은 다음과 같습니다.

int 형은 32bit 를 유지합니다.
short 형은 16bit 를 유지합니다.
long 형은 32bit에서 64bit로 확장됩니다.
long long 형은 64bit 를 유지합니다.
pointer 형은 32bit 에서 64bit로 확장딥니다.
long double 형이 12bytes 에서 16bytes로 확장됩니다.
size_t과 ssize_t 형이 32bit 에서 64bit 로 확장됩니다.
이와 관련된 typedef 문 역시 확장됩니다.


2. 64bit linux platforms

코드:
 Architecture    | uname -m | Size | Endian | Libpath | Miscellaneous
----------------+----------+------+--------+---------+--------------------------------
Alpha           | alpha    | LP64 | little | lib     |
AMD64           | x86_64   | LP64 | little | lib64   | executes x86 code natively
IPF             | ia64     | LP64 | little | lib     | executes x86 code via emulation
MIPS64          | mips64   | LP64 | both   | lib64   | executes MIPS code natively
PowerPC64       | ppc64    | LP64 | big    | lib64   | executes PowerPC code natively
Sparc64         | sparc64  | LP64 | big    | lib64   | executes Sparc code natively
PA-RISC64       | parisc64 | LP64 | big    | -       | only kernel support, no 64-bit
                 |          |      |        |         | executes 32-bit PA-RISC code
zSeries (s390x) | s390x    | LP64 | big    | lib64   | executes s390 code natively


3. 문제가 되는 코드들

(1) 크기가 다른 변수형에 대한 포인터를 사용한 경우 (스택붕괴가 우려되는 경우)
getsockopt의 size인자가 socklen_t 로 정의되는 경우 아래의 코드는 s_socklen 변수를 int로 정의한것에서 문제가 발생할수 있습니다.
코드:
int s_socklen;
s_result = getsockopt(s_socket, s_level, s_optname, &s_optval, &s_socklen);

이것은 다음과 같이 변경되어야 합니다. 이것은 int와 socklen_t 는 크기가 다르기 때문입니다.
코드:
socklen_t s_socklen;
s_result = getsockopt(s_socket, s_level, s_optname, &s_optval, &s_socklen);


(2) 조건식을 int 로 받는 함수에 포인터를 넘겨줄경우 (컴파일러 경고)
일반적으로 다음과 같은 함수가 있을때
코드:
void my_assert(int s_expression)
{
if(!s_expression)return;
(void)fprintf(stderr, "assert....\n");
}

위와 같은 함수에 조건문을 사용할때
코드:
void *s_ptr = NULL;
my_assert(s_ptr);

다음과 같이 변경하여야 합니다.
코드:
void *s_ptr = NULL;
my_assert(s_ptr != NULL);

이것은 포인터가 int 형과 다른 크기이므로 포인터는 int로 casting 되면서 잘리게 되고 NULL포인터가 아님에도 하위 32bit가 0인경우 my_assert 는 의도하지 않은 동작을 할수 있기 때문입니다.

(3) dword 정의 (만약 이렇게 써왔다면..)
다음과 같이 my_DWORD를 정의하여 사용했다면
코드:
#define my_DWORD unsigned long int

다음과 같이 변경하여야 합니다.
코드:
#define my_DWORD unsigned int


(4) x86계열 어셈블리 호환성 (안바꿔도 동작한다.)
예를 들어서 atomic exchange 를 다음과 같이 C함수로 구현했다면
코드:

int my_atomic_exchange(int * volatile s_to, int s_value)
{
__asm volatile ("xchgl (%2), %0\n\t" : "=r"(s_value) : "0"(s_value), "r"(s_to) : "memory");
return(s_value);
}

전혀 수정할 필요없이 그대로 컴파일 가능합니다. 하지만 int형이 아닌 long 형을 사용했다면 register 는 eax, ebx, .. 가 아닌 rax, rbx, ... 로 변경을 고려해야 합니다.

(5) implementation 함수의 잘못된 고려 (size_t 등의 의미를 전혀 활용하지 못한경우 포팅이 쉽지 않을수 있음.)
예를 들어서 memcpy 를 한번 감싸서 다음과 같이 자신만의 함수를 만들었다면
코드:
void *my_memcpy(void *s_to, const void *s_from, int s_size)
{
return(memcpy(s_to, s_from, s_size));
}

당연히 s_size 변수는 64bit를 담을수 없는 그릇으로 전달되기 때문에 원하지 않은 결과를 발생할수 있습니다. 때문에 다음과 같이 변경되어야 합니다.
코드:
void *my_memcpy(void *s_to, const void *s_from, size_t s_size)
{
return(memcpy(s_to, s_from, s_size));
}

size_t, ssize_t 의 용도를 전혀 중요하게 생각지 않은 개발자라면 이 문제로 64bit 포팅에 좌절을 겪을수도 있습니다. 고려하지 않은 개발자분들은 위의 예제처럼 memcpy 에서보다는 memory offset 연산에서 후회할수 있습니다.

(6) 정렬
기존에는 구조체의 sizeof() 에 의한 정렬된 값이 보통 4byte align로 사용되었으나 이것은 이제 기본값으로 믿을수 없습니다. 이제는 보통 8byte align 이 기본값으로 사용됩니다. 때문에 반드시 의도적으로 align을 해야 되는 경우라면 다음과 같이 작성되어야 합니다. (이것은 뻔한 내용이지만 그것을 이야기 하려고 한것이 아니고 신중한 library 개발자라면 모든 구조체는 명시적으로 align 을 지정해줘야 될수 있다는 것을 말합니다.)
코드:
#pragma pack(push,8)
struct ts_my_struct
{
unsigned char b;
unsigned short w;
unsigned int d;
unsigned long d;
unsigned long long q;
long double paragraph;
}
#pragma pack(pop)


(7) predefine 으로 64bit 를 검출
각 architecture 별 predefine의 종류가 많아서 간단하게 검출할수 있는 내용은 아니지만 제가 지금까지 포팅한 architecture는 다음과 같이 하여 검출하였습니다. 사실 이것이 모두 완벽하게 검출한다고 할수는 없습니다. 들어보지도 못한 architecture도 많으니까..
코드:
#if defined(__x86_64__) || defined(__ia64__) || defined(_M_AMD64) || defined(_M_IA64) || defined(_WIN64) || defined(__alpha__) || defined(__s390__) /* ... */
/* 오~ 나 64bit 에서 컴파일 되네.. 어허 요렇게 처리하자~ */
#endif
크리에이티브 커먼즈 라이센스
Creative Commons License
Posted by minzkn

트랙백 주소 :: http://blog.minzkn.com/trackback/197

댓글을 달아 주세요