Skip to the content.

BL / BLR 명령어 (Branch with Link)

Summary

정의: 함수 호출(subroutine call)을 수행하는 명령어. 분기와 동시에 복귀 주소를 LR(X30)에 자동 저장하는 것이 핵심 특징임. B와의 근본적 차이는 바로 이 “Link” 동작임.


BL vs BLR — 목표 주소 지정 방식의 차이

니모닉 정식 명칭 목표 주소 방식 범위
BL Branch with Link 라벨(즉치값, PC 상대) ±128MB
BLR Branch with Link to Register 레지스터 값 (절대 주소) 무제한 (레지스터 64비트 전체)

핵심 판단 기준: 호출할 함수의 주소가 컴파일 시점에 고정되어 있는지, 런타임에 결정되는지에 따라 선택이 갈림.


BL — 정적 함수 호출

문법:

BL label

동작:

  1. 다음 실행할 명령어 주소(복귀 주소)를 LR(X30)에 저장
  2. label 위치로 무조건 분기

범위 제약: PC 기준 ±128MB (offset이 26비트로 인코딩되며, 4바이트 단위이므로 26비트 × 4 = 128MB 커버)

용도: 소스 코드 상에서 함수명을 직접 호출하는 거의 모든 일반적인 함수 호출에 사용됨.

.global _start
.align 2

.text
_start:
    bl  my_function      // my_function 호출, 복귀주소가 LR에 저장됨
    
    mov x0, #0
    mov x16, #1
    svc #0x80

my_function:
    mov x0, #42
    ret                    // LR에 저장된 주소로 복귀

BLR — 동적 함수 호출

문법:

BLR Xn

동작:

  1. 다음 실행할 명령어 주소를 LR(X30)에 저장
  2. 레지스터 Xn에 담긴 주소로 분기

범위 제약: 없음 (64비트 레지스터 전체 주소 공간 커버)

용도: 함수 포인터, 가상 함수 테이블(vtable), 동적 라이브러리 심볼 등 런타임에 계산되거나 결정되는 주소를 호출할 때 사용됨.

.text
_start:
    adrp x0, my_function@PAGE
    add  x0, x0, my_function@PAGEOFF   // 함수 주소를 레지스터에 로드

    blr x0                                 // 레지스터에 담긴 주소로 호출

    mov x0, #0
    mov x16, #1
    svc #0x80

my_function:
    mov x0, #42
    ret

실전 활용 예시 — BLR이 필요한 상황

상황 이유
함수 포인터 호출 (C언어의 void (*fp)()) 호출 대상이 변수에 담긴 주소이므로 컴파일 시점에 고정 불가
가상 함수 / vtable (C++, Objective-C 메시지 디스패치) 객체 타입에 따라 실제 호출 함수가 런타임에 결정됨
PLT(Procedure Linkage Table)를 통한 동적 라이브러리 호출 라이브러리가 로드되는 실제 메모리 주소는 실행 시점에 결정됨
콜백 함수 호출자가 함수 주소를 매개변수로 전달받아 실행

Objective-C 관련 참고: macOS/iOS 바이너리에서 objc_msgSend 호출 패턴을 분석하다 보면 BL objc_msgSend(정적 심볼 호출)와 BLR(vtable 기반 동적 디스패치)이 혼재되어 나타나는 경우를 자주 볼 수 있음.


LR 저장 시 주의사항 (이전 LR 설명과 연결)

중요: BL/BLR 모두 LR(X30)을 자동으로 덮어씀. 따라서 함수 내부에서 다시 BL/BLR로 다른 함수를 호출하는 경우(nested call), 기존 LR 값을 잃어버리기 전에 스택에 저장해야 함.

my_function:
    stp x29, x30, [sp, #-16]!   // LR(x30) 스택 저장

    bl  another_function          // LR 갱신됨 (another_function 호출용)

    ldp x29, x30, [sp], #16      // 원래 LR 복원
    ret                            // 복원된 LR로 정상 복귀

Leaf function(잎 함수, 내부에서 다른 함수를 호출하지 않는 함수) 은 이 저장/복원 과정이 불필요함. 컴파일러도 이런 경우 스택 프레임 설정을 생략하여 최적화함.


B vs BL vs BLR 종합 비교

니모닉 Link(LR 저장) 목표 지정 방식 대표 용도
B 안 함 라벨 단순 분기, 루프, if문
BL 라벨 정적 함수 호출
BLR 레지스터 함수 포인터, vtable, 동적 호출

정리하자면: BL은 “어디로 갈지 미리 아는” 대부분의 함수 호출에, BLR은 “어디로 갈지 실행해봐야 아는” 동적 디스패치 상황에 사용되는 명령어임. 컴파일된 일반 애플리케이션 코드에서 실제 빈도로는 BL이 압도적으로 많이 관찰되며, BLR은 객체지향 언어의 다형성이나 함수 포인터를 많이 쓰는 코드에서 상대적으로 자주 등장함.