有时 gcc 在编译 arm abi 的 C++ 代码时会将第一个参数放入 R1 寄存器?

Sometimes gcc would put the first argument into R1 register when compiling the C++ code for arm abi?

从 ARM 到 C 的调用约定,我知道参数是从寄存器 r0-r4 开始按顺序传递的,然后对于其他参数使用堆栈。 Return 值传递给 r0-r1。

但是在libart.so(AndroidM,/system/lib/libart.so,32bit)中,有一个方法好像不符合规则。

//https://android.googlesource.com/platform/art/+/android-6.0.0_r5/runtime/oat_file.cc
std::unique_ptr<const DexFile> OatFile::OatDexFile::OpenDexFile(std::string* error_msg) const {
    return DexFile::Open(dex_file_pointer_, FileSize(), dex_file_location_,
                       dex_file_location_checksum_, this, error_msg);
}

//https://android.googlesource.com/platform/art/+/android-6.0.0_r5/runtime/dex_file.h
static std::unique_ptr<const DexFile> DexFile::Open(const uint8_t* base, size_t size,
                                             const std::string& location,
                                             uint32_t location_checksum,
                                             const OatDexFile* oat_dex_file,
                                             std::string* error_msg) {
    return OpenMemory(base, size, location, location_checksum, nullptr, oat_dex_file, error_msg);
}

OpenDexfile 是 OatDexFile class 的一个成员函数,它是 OatFile class 的内部 class。所以 OpenDexFile 实际上有 2 个参数,因为第一个参数是 "this"。 但在 IDA Pro 中,OpenDexFile 如下所示:

.text:002E9718 var_14          = -0x14
.text:002E9718 var_4           = -4
.text:002E9718
.text:002E9718   STR.W           R4, [SP,#var_14]!
.text:002E971C   MOV             R4, R1   ;<<--After analysing, I can assure that R1 is the "this" pointer
.text:002E971E   LDR             R1, [R1,#0x20] ;<<---dex_file_pointer
.text:002E9720   STRD.W          R5, R6, [SP,#4]
.text:002E9724   ADDS            R3, R4, #4
.text:002E9726   MOV             R5, R0 ;<<---It seems like that r0 is added but not for the "this" pointer
.text:002E9728   STRD.W          R7, LR, [SP,#0xC]
.text:002E972C   LDR.W           LR, [R4,#0x1C]
.text:002E9730   SUB             SP, SP, #0x14
.text:002E9732   MOVS            R7, #0
.text:002E9734   LDR             R6, [R1,#0x20]
.text:002E9736   STRD.W          R4, R2, [SP,#8]  ;<<--R2 represent the arg "error_msg"
.text:002E973A   STRD.W          LR, R7, [SP]
.text:002E973E   MOV             R2, R6
.text:002E9740   BL     DexFile::OpenMemory ;<<---DexFile::Open is a inline function. When executing this instruction, r0 equals r5.
.text:002E9744   MOV             R0, R5;<<--OpenMemory is also a bit weird. It looks like that OpenMemory also adds r0 for the return value, because r0 equals r5 before calling OpenMemory
.text:002E9746   ADD             SP, SP, #0x14
.text:002E9748   LDRD.W          R4, R5, [SP]
.text:002E974C   LDRD.W          R6, R7, [SP,#8]
.text:002E9750   ADD             SP, SP, #0x10
.text:002E9752   LDR.W           PC, [SP+4+var_4],#4

我只是想知道是否存在一种特殊情况,其中 "this" 指针将被放入 R1 而不是 R0,并且参数从寄存器 r1 开始按顺序传递。 如果你能帮助我,我将不胜感激。

检查 arm ABI 第 5.5 章

R0:对于 return 值

R1-R3加栈:用于传递参数

来自Procedure Call Standard

If the subroutine is a function that returns a result in memory, then the address for the result is placed in r0 and the NCRN is set to r1.

OpenDexFile

是(可能)返回一个 DexFile 对象,该对象需要放置内存,因此 r0r1 变为 this.

这个之前已经讲过:the order of C++ implicit arguments: this and the returned object, which goes first?

一般注意事项是 ARM ABI 与 Itanium ABI 类似。如果您在查看 ARM ABI 后找不到要研究的资源,您也可以查看那个。