한 4년 전 인가요? 아래 코드를 열심히 분석 했었어요. 그런데 나중에 알고 보니 CONFIG_KMEMCHECK, CONFIG_LOCKDEP 컨피그 내 코드가 컴파일 되지 않는 죽은 코드라는 걸 알게 되었어요. 그 때 참 머리를 쥐어 뜯으며 자책했죠. 
static inline void slab_free_hook(struct kmem_cache *s, void *x)
{

 

 kmemleak_free_recursive(x, s->flags);
 
 /*
  * Trouble is that we may no longer disable interrupts in the fast path
  * So in order to make the debug calls that expect irqs to be
  * disabled we need to disable interrupts temporarily.
  */
#if defined(CONFIG_KMEMCHECK) || defined(CONFIG_LOCKDEP)
 {
  unsigned long flags;
 
  local_irq_save(flags);
  kmemcheck_slab_free(s, x, s->object_size);
  debug_check_no_locks_freed(x, s->object_size);
  local_irq_restore(flags);
 }
#endif
 if (!(s->flags & SLAB_DEBUG_OBJECTS))
  debug_check_no_obj_freed(x, s->object_size);
 
 kasan_slab_free(s, x);
 
}
 
이 사실을 어떻게 알아 냈나면, 전처리 파일을 보고 나서죠.
전처리 파일로 slab_free_hook() 함수 구현부를 보았더니 완전 다른 코드로 바뀌어 있었어요.
SLAB_DEBUG_OBJECTS 매크로가 0x00000000UL로 뒤바꾸어 있네요.
static inline __attribute__((always_inline)) __attribute__((no_instrument_function)) void slab_free_hook(struct kmem_cache *s, void *x)
{
 kmemleak_free_recursive(x, s->flags);
# 1314 "/home001/kernel_lover/kernel/mm/slub.c"
 if (!(s->flags & 0x00000000UL))
  debug_check_no_obj_freed(x, s->object_size);
 
 kasan_slab_free(s, x);
}
 
다른 예를 살펴볼까요? get_partial_node() 함수 내 너무나도 유명한 list_for_each_entry_safe API가 보이죠.
static void *get_partial_node(struct kmem_cache *s, struct kmem_cache_node *n,
    struct kmem_cache_cpu *c, gfp_t flags)
{
 struct page *page, *page2;
 void *object = NULL;
 int available = 0;
 int objects;
 
 if (!n || !n->nr_partial)
  return NULL;
 
 spin_lock(&n->list_lock);
 list_for_each_entry_safe(page, page2, &n->partial, lru) {
  void *t;
 
  if (!pfmemalloc_match(page, flags))
   continue;
 
  t = acquire_slab(s, n, page, object == NULL, &objects);
//skip
 }
 spin_unlock(&n->list_lock);
 
list_for_each_entry_safe 함수를 전처리 파일로 보면 어떨까요?
어라, 참 다르죠.
static void *get_partial_node(struct kmem_cache *s, struct kmem_cache_node *n,
    struct kmem_cache_cpu *c, gfp_t flags)
{
 struct page *page, *page2;
 void *object = ((void *)0);
 int available = 0;
 int objects;
 
 
 if (!n || !n->nr_partial)
  return ((void *)0);
 
 spin_lock(&n->list_lock);
 for (page = ({ const typeof( ((typeof(*page) *)0)->lru ) *__mptr = ((&n->partial)->next); (typeof(*page) *)( (char *)__mptr - __builtin_offsetof(typeof(*page), lru) );}), page2 = ({ const typeof( ((typeof(*(page)) *)0)->lru ) *__mptr = ((page)->lru.next); (typeof(*(page)) *)( (char *)__mptr - __builtin_offsetof(typeof(*(page)), lru) );}); &page->lru != (&n->partial); page = page2, page2 = ({ const typeof( ((typeof(*(page2)) *)0)->lru ) *__mptr = ((page2)->lru.next); (typeof(*(page2)) *)( (char *)__mptr - __builtin_offsetof(typeof(*(page2)), lru) );})) {
  void *t;
 
또 다른 예를 살펴볼까요?
static void init_pwq(struct pool_workqueue *pwq, struct workqueue_struct *wq,
       struct worker_pool *pool)
{
 BUG_ON((unsigned long)pwq & WORK_STRUCT_FLAG_MASK);
 
 memset(pwq, 0, sizeof(*pwq));
 
 pwq->pool = pool;
 
역시 전처리 파일 내 함수는 다르게 구현되어 있네요.
static void init_pwq(struct pool_workqueue *pwq, struct workqueue_struct *wq,
       struct worker_pool *pool)
{
 do { if (__builtin_expect(!!((unsigned long)pwq & WORK_STRUCT_FLAG_MASK), 0)) do { asm volatile(".long " "((0xe7f001f2) & 0xFFFFFFFF)" "\n\t" "\n"); __builtin_unreachable(); } while (0); } while (0);
 
 ({ void *__p = (pwq); size_t __n = sizeof(*pwq); if ((__n) != 0) { if (__builtin_constant_p((0)) && (0) == 0) __memzero((__p),(__n)); else memset((__p),(0),(__n)); } (__p); });
 
 pwq->pool = pool;
 
 
전처리 파일을 추출은 하는 방법이 뭐냐구요?
아래 패치를 적용하고 커널 컴파일을 하세요. 그럼 리눅스 커널 오브젝트 파일이 생기는 디렉토리에
.tmp_slub.i 형태로 생성되요.
 
diff --git a/Makefile b/Makefile
index b03ca98..f52240c 100644
--- a/Makefile
+++ b/Makefile
@@ -406,6 +406,7 @@ KBUILD_CFLAGS   := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
      -fno-strict-aliasing -fno-common \
      -Werror-implicit-function-declaration \
      -Wno-format-security \
+     -save-temps=obj \
      -std=gnu89

+ Recent posts