1000sj
SJ CODE
1000sj
전체 방문자
오늘
어제
  • 분류 전체보기 N
    • Security N
      • 네트워크
      • 보안
      • CTF
      • Exploit
      • Fuzzing N
    • System Programming
      • Kernel
      • Operating System
      • Compiler
      • Device Driver
      • Emulator
      • Parrelel Processing
      • Assembly
    • Application Programming
      • Script
      • Android
    • Cloud Computing
      • Cloud Native
      • Public Cloud
      • Infrastructure
      • Database
      • DevOps
    • TroubleShooting
    • ETC
      • 문화 생활
      • 커뮤니티

인기 글

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
1000sj

SJ CODE

System Programming/Compiler

LLVM tutorial - Clang SanitizerCoverage 분석

2025. 12. 2. 23:45

 

#include <stdio.h>

void handle_positive(void) {
    printf("Positive!\n");
}

void handle_negative(void) {
    printf("Negative!\n");
}

void cleanup(void) {
    printf("Cleanup!\n");
}

void process(int x) {
    if (x > 0) {
        handle_positive();
    } else {
        handle_negative();
    }
    cleanup();
}

int main() {
    process(5);
    process(-3);
    return 0;
}

 

SanitizerCoverage로 컴파일하여 어셈블리 확인

clang -S -O1 -fsanitize-coverage=trace-pc,trace-cmp -o test_coverage.s test_coverage.c 2>&1

 

grep -A 50 "^process:" test_coverage.s | head -60
process:                                # @process
	.cfi_startproc
# %bb.0:
	pushq	%rbx
	.cfi_def_cfa_offset 16
	.cfi_offset %rbx, -16
	movl	%edi, %ebx
	callq	__sanitizer_cov_trace_pc@PLT
	xorl	%edi, %edi
	movl	%ebx, %esi
	callq	__sanitizer_cov_trace_const_cmp4@PLT
	testl	%ebx, %ebx
	movl	$.Lstr, %eax
	movl	$.Lstr.3, %edi
	cmovgq	%rax, %rdi
	callq	puts@PLT
	movl	$.Lstr.4, %edi
	popq	%rbx
	.cfi_def_cfa_offset 8
	jmp	puts@PLT                        # TAILCALL
.Lfunc_end3:
	.size	process, .Lfunc_end3-process
	.cfi_endproc
                                        # -- End function
	.globl	main                            # -- Begin function main
	.p2align	4
	.type	main,@function
main:                                   # @main
	.cfi_startproc
# %bb.0:
	pushq	%rax
	.cfi_def_cfa_offset 16
	callq	__sanitizer_cov_trace_pc@PLT
	movl	$.Lstr, %edi
	callq	puts@PLT
	movl	$.Lstr.4, %edi
	callq	puts@PLT
	movl	$.Lstr.3, %edi
	callq	puts@PLT
	movl	$.Lstr.4, %edi
	callq	puts@PLT
	xorl	%eax, %eax
	popq	%rcx
	.cfi_def_cfa_offset 8
	retq
.Lfunc_end4:
	.size	main, .Lfunc_end4-main
	.cfi_endproc
                                        # -- End function
	.type	.Lstr,@object                   # @str
	.section	.rodata.str1.1,"aMS",@progbits,1

 

최적화 없이 컴파일하여 기본 블록 분리 확인

clang -S -O0 -fsanitize-coverage=trace-pc,trace-cmp -o test_no_opt.s test_coverage.c 2>&1

 

grep -A 80 "^process:" test_no_opt.s | head -85
process:                                # @process
	.cfi_startproc
# %bb.0:
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	subq	$16, %rsp
	movl	%edi, -12(%rbp)                 # 4-byte Spill
	callq	__sanitizer_cov_trace_pc@PLT
	movl	-12(%rbp), %edi                 # 4-byte Reload
	movl	%edi, -4(%rbp)
	movl	-4(%rbp), %esi
	movl	%esi, -8(%rbp)                  # 4-byte Spill
	xorl	%edi, %edi
	callq	__sanitizer_cov_trace_const_cmp4@PLT
	movl	-8(%rbp), %eax                  # 4-byte Reload
	cmpl	$0, %eax
	jle	.LBB3_2
# %bb.1:
	callq	__sanitizer_cov_trace_pc@PLT
	callq	handle_positive
	jmp	.LBB3_3
.LBB3_2:
	callq	__sanitizer_cov_trace_pc@PLT
	callq	handle_negative
.LBB3_3:
	callq	cleanup
	addq	$16, %rsp
	popq	%rbp
	.cfi_def_cfa %rsp, 8
	retq
.Lfunc_end3:
	.size	process, .Lfunc_end3-process
	.cfi_endproc
                                        # -- End function
	.globl	main                            # -- Begin function main
	.p2align	4
	.type	main,@function
main:                                   # @main
	.cfi_startproc
# %bb.0:
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	subq	$16, %rsp
	callq	__sanitizer_cov_trace_pc@PLT
	movl	$0, -4(%rbp)
	movl	$5, %edi
	callq	process
	movl	$4294967293, %edi               # imm = 0xFFFFFFFD
	callq	process
	xorl	%eax, %eax
	addq	$16, %rsp
	popq	%rbp
	.cfi_def_cfa %rsp, 8
	retq
.Lfunc_end4:
	.size	main, .Lfunc_end4-main
	.cfi_endproc
                                        # -- End function
	.type	.L.str,@object                  # @.str
	.section	.rodata.str1.1,"aMS",@progbits,1
.L.str:
	.asciz	"Positive!\n"
	.size	.L.str, 11

	.type	.L.str.1,@object                # @.str.1
.L.str.1:
	.asciz	"Negative!\n"
	.size	.L.str.1, 11

	.type	.L.str.2,@object                # @.str.2
.L.str.2:
	.asciz	"Cleanup!\n"
	.size	.L.str.2, 10

	.ident	"clang version 21.1.6 (Fedora 21.1.6-1.fc43)"

 

트레이싱 없이 컴파일하여 비교

clang -S -O0 -o test_normal.s test_coverage.c

 

grep -A 35 "^process:" test_normal.s | head -40
process:                                # @process
	.cfi_startproc
# %bb.0:
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	subq	$16, %rsp
	movl	%edi, -4(%rbp)
	cmpl	$0, -4(%rbp)
	jle	.LBB3_2
# %bb.1:
	callq	handle_positive
	jmp	.LBB3_3
.LBB3_2:
	callq	handle_negative
.LBB3_3:
	callq	cleanup
	addq	$16, %rsp
	popq	%rbp
	.cfi_def_cfa %rsp, 8
	retq
.Lfunc_end3:
	.size	process, .Lfunc_end3-process
	.cfi_endproc
                                        # -- End function
	.globl	main                            # -- Begin function main
	.p2align	4
	.type	main,@function
main:                                   # @main
	.cfi_startproc
# %bb.0:
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16

 

C 코드를 LLVM IR로 변환

clang -S -emit-llvm -O0 -o test.ll test_coverage.

 

grep -A 30 "define.*@process" test.ll
define dso_local void @process(i32 noundef %0) #0 {
  %2 = alloca i32, align 4
  store i32 %0, ptr %2, align 4
  %3 = load i32, ptr %2, align 4
  %4 = icmp sgt i32 %3, 0
  br i1 %4, label %5, label %6

5:                                                ; preds = %1
  call void @handle_positive()
  br label %7

6:                                                ; preds = %1
  call void @handle_negative()
  br label %7

7:                                                ; preds = %6, %5
  call void @cleanup()
  ret void
}

; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @main() #0 {
  %1 = alloca i32, align 4
  store i32 0, ptr %1, align 4
  call void @process(i32 noundef 5)
  call void @process(i32 noundef -3)
  ret i32 0
}

attributes #0 = { noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #1 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }

 

opt 사용 (LLVM 15 이상)하여 CFG DOT 파일 생성

$ opt -passes=dot-cfg test.ll -disable-output
Writing '.handle_positive.dot'...
Writing '.handle_negative.dot'...
Writing '.cleanup.dot'...
Writing '.process.dot'...
Writing '.main.dot'...

 

PNG로 변환

dot -Tpng .process.dot -o process_cfg.png

 

References

  • https://llvm.org/devmtg/2011-11/
  •  

'System Programming > Compiler' 카테고리의 다른 글

LLVM tutorial #0 Architecture  (0) 2025.10.11
    'System Programming/Compiler' 카테고리의 다른 글
    • LLVM tutorial #0 Architecture
    1000sj
    1000sj

    티스토리툴바