테스트 없는 C 코드 포팅하기


주의사항

여기서 제안하는 건 어디까지나 하나의 방법론일 뿐이며, 이게 최선의 방법이라는 보장은 없습니다.

문제

여기 어떤 C 코드가 있습니다. 최종적으로 이게 게임 코드이긴 한데 어떤 원리로 돌아가는지 100% 파악된 것은 아닙니다. 제한된 정보 하에서 어떻게 하면 코드의 동작원리를 분석할 수 있을까요?

제안 1 - struct 정의를 만들어보자

몇몇 코드 중에선 포인터에 integer arithmetic을 해서 멤버를 접근하는 경우가 있습니다. 보통 이런 것들은 원래 C 코드가 struct 혹은 class를 정의했는데 디어셈블 과정에서 struct의 정보는 날아가 버리고 특정 주소에 접근한 것들만 남은 경우죠.

이런 코드는 struct가 있다고 가정하고 각 멤버 접근을 struct의 field로 정의해봐서, 해당 가정이 맞는지 검증해볼 수 있습니다.

가정이 완벽하지 않아서 중간에 필드가 비어있는 경우가 있다면 해당 부분은 그냥 버퍼로 임시땜방을 쳐 놓고 하는거죠. 다만 버퍼 영역의 크기는 정확히 원래 C 코드랑 맞아떨어져야 합니다.

대충 정의를 만들었다 가정하면, 해당 포인터 접근을 struct의 멤버 접근으로 바꿔서 코드를 읽어보면 더 이해하기 쉬워질 수 있습니다.

가능하면 원래 코드를 그대로 두고 필드 선언만 해 둔 다음에, 각 필드의 값을 로그로 출력해서 원래 의도한 필드 정의와 부합하는지 확인해보고 이후에 코드를 변환하는 것이 더 안전하겠죠?

예제: https://github.com/noxworld-dev/opennox/pull/698

제안 2 - 모듈 boundary를 설정해 보자

특정 변수를 읽고 쓰는 코드를 한곳에 모으고, 그 코드들이 접근하는 다른 변수들도 같이 모으다 보면 어느정도 모듈의 경계를 알 수 있습니다.

C 코드다보니 개발자가 대충 접근 권한을 마구 퍼뜨려서 해당 접근이 쉽지 않을 가능성도 분명 있지만, 어쨌든 조금이나마 경계를 만들어 보면 해당 모듈이 어떤 역할을 하는지 알 수 있습니다.

마찬가지로 각 변수들을 그대로 둔 채, 해당 변수를 레퍼런스하는 포인터들을 만들어서 로그로 찍어 확인해보면 내가 제대로 짜고 있는지 확인할 수 있겠죠?

예제: https://github.com/noxworld-dev/opennox/pull/703

결론

그치만 갈길이 멀다…