MultiCanary Intrinsic Functionの実装

  • Intrinsic Functionとして実装するのがやっぱりキレイ
  • なぜalloca i8*しているのかやっぱりわからない
  • FastISelを無効化してアセンブリに違いがあるか見てみよう→同じだった
 %2 = alloca [38 x i8], align 16
 %Canary = load volatile i8*, i8* addrspace(257)* inttoptr (i32 40 to i8* addrspace(257)*)
 %CanaryCast = bitcast i8* %Canary to i64*
 %CanaryX = ptrtoint i64* %CanaryCast to i64
 %CanaryGEP = getelementptr inbounds [38 x i8], [38 x i8]* %2, i32 0, i32 30
 %CanaryGEPT = bitcast i8* %CanaryGEP to i64*
 store i64 %CanaryX, i64* %CanaryGEPT
 // なぜalloca i8ではないのか?
 %StackGuardSlot = alloca i8*
 %StackGuard = load volatile i8*, i8* addrspace(257)* inttoptr (i32 40 to i8* addrspace(257)*)
 call void @llvm.stackprotector(i8* %StackGuard, i8** %StackGuardSlot)
 %23:gr64 = MOV64rm %noreg, 1, %noreg, 40, %fs; mem:Volatile LD8[inttoptr (i32 40 to i8* addrspace(257)*)(addrspace=257)] GR64:%23
 MOV64mr %stack.0.StackGuardSlot, 1, %noreg, 0, %noreg, killed %23; GR64:%23

	`i8* addrspace(257)*` = `(i8* addrspace(257)) *` = fsにいるi8*へのポインタ
	`void*`がないので代わりに`i8*`を使っているだけか?
		>Note that LLVM does not permit pointers to void (void*) nor does it permit pointers to labels (label*). Use i8* instead.
		https://llvm.org/docs/LangRef.html#pointer-type
	ポインタ型と同じサイズになっているからそのサイズぶん確保しているだけっぽい

	libc_start_mainを追ってみると
	code:glibc/csu/libc-start.c
	 STATIC int LIBC_START_MAIN (int (*main) (int, ...
	 
    /* Set up the stack checker's canary.  */
    uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard (_dl_random);
  # ifdef THREAD_SET_STACK_GUARD
    THREAD_SET_STACK_GUARD (stack_chk_guard);
  # else
    __stack_chk_guard = stack_chk_guard;
  # endif
  
    ...
	code:glibc/sysdeps/unix/sysv/linux/dl-osinfo.h
	 static inline uintptr_t __attribute__ ((always_inline))
  _dl_setup_stack_chk_guard (void *dl_random) {
    union
    {
      uintptr_t num; // 定義がもうそうなっているのか
      unsigned char bytes[sizeof (uintptr_t)];
    } ret;
  
    /* We need in the moment only 8 bytes on 32-bit platforms and 16
       bytes on 64-bit platforms.  Therefore we can use the data
       directly and not use the kernel-provided data to seed a PRNG.  */
    memcpy (ret.bytes, dl_random, sizeof (ret));
    ...
    return ret.num;
  }

	LocalStackSlotPass::calculateFrameObjectOffsets (LSS)
	PrologEpilogInserter::calculateFrameObjectOffsets (PEI)
	この2つでStackProtectorの処理が重複している
	code:CodeGen/LocalStackSlotAllocation.cpp
		   // And tell MFI about it for PEI to use later
     MFI.mapLocalFrameObject(FrameIdx, LocalOffset);
	code:include/llvm/CodeGen/MachineFrameInfo.h
		   /// Map a frame index into the local object block
     void mapLocalFrameObject(int ObjectIndex, int64_t Offset) {
       LocalFrameObjects.push_back(std::pair<int, int64_t>(ObjectIndex, Offset));
       Objects[ObjectIndex + NumFixedObjects].PreAllocated = true;
     }
	base registerが存在しない?ときにはLSSの情報は破棄されるのでPEIに書くほうがよさそう
		よくわからん insertFrameReferenceRegisters
	fixed stack?

	>Note that any intrinsic using one of the llvm_any*_ty types for an argument or return type will be deemed by tblgen as overloaded and the corresponding suffix will be required on the intrinsic’s name.
		[https://llvm.org/docs/ExtendingLLVM.html]
	AllocaInstは任意の型オブジェクトへのポインタ型なので、llvm_any(ptr)_tyを使う必要がある
	使用時には型も指定してあげる
		code:MultiCanary.cpp
			B.CreateCall(Intrinsic::getDeclaration(M, Intrinsic::multicanary, {AI->getType()}), {LI, CanaryAI, AI});
		code:IR
		 %result = call i64 @llvm.read_register.i64(metadata !0) #5

	code:twobuf_opt_llc.txt
  5(canary) for 6
  1 for 2
  3 for 4
  ...
  alloc FI(0) at SP[-24]
  alloc FI(4) at SP[-64]
  alloc FI(6) at SP[-96]
  alloc FI(1) at SP[-104]
  alloc FI(2) at SP[-108]
  alloc FI(3) at SP[-120]
  alloc FI(5) at SP[-128]
	正しい場所に配置されてない
	SelectionDAGからProlog/Epilog Insertionまでの間に、Objectが挿入されてIndexが変化したのが原因だった
	他の関数を見ると`Objects[FI + NumFixedObjects]`のようにして取得している
	なるほどね

Backlinks