Skip to content

Commit ef29b0b

Browse files
committed
Move register class and register list default from core to api.
1 parent d7deae3 commit ef29b0b

File tree

5 files changed

+493
-87
lines changed

5 files changed

+493
-87
lines changed

arch/riscv/src/lib.rs

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use binaryninja::{
1616
},
1717
binary_view::{BinaryView, BinaryViewExt},
1818
calling_convention::{
19-
register_calling_convention, CallingConvention, ConventionBuilder, RegisterListKind,
19+
register_calling_convention, CallingConvention, ConventionBuilder,
2020
},
2121
custom_binary_view::{BinaryViewType, BinaryViewTypeExt},
2222
disassembly::{InstructionTextToken, InstructionTextTokenKind},
@@ -2844,27 +2844,6 @@ impl<D: RiscVDisassembler> CallingConvention for RiscVCC<D> {
28442844
fn are_argument_registers_used_for_var_args(&self) -> bool {
28452845
true
28462846
}
2847-
2848-
// Register-list/class based API - default implementations for simple calling convention
2849-
fn register_argument_classes(&self) -> Vec<u32> {
2850-
Vec::new()
2851-
}
2852-
2853-
fn register_argument_class_lists(&self, _class_id: u32) -> Vec<u32> {
2854-
Vec::new()
2855-
}
2856-
2857-
fn register_argument_lists(&self) -> Vec<u32> {
2858-
Vec::new()
2859-
}
2860-
2861-
fn register_argument_list_regs(&self, _reg_list_id: u32) -> Vec<RegisterId> {
2862-
Vec::new()
2863-
}
2864-
2865-
fn register_argument_list_kind(&self, _reg_list_id: u32) -> RegisterListKind {
2866-
RegisterListKind::IntegerSemantics
2867-
}
28682847
}
28692848

28702849
struct RiscVELFPLTRecognizer;

binaryninjaapi.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16762,7 +16762,7 @@ namespace BinaryNinja {
1676216762
virtual std::vector<uint32_t> GetRegisterArgumentListRegs(uint32_t regListId);
1676316763
virtual BNRegisterListKind GetRegisterArgumentListKind(uint32_t regListId);
1676416764
virtual std::vector<Variable> GetVariablesForParameters(const std::vector<FunctionParameter>& paramTypes,
16765-
const std::set<uint32_t>* permittedRegs = nullptr);
16765+
const std::optional<std::set<uint32_t>>& permittedRegs = std::nullopt);
1676616766

1676716767
virtual uint32_t GetIntegerReturnValueRegister() = 0;
1676816768
virtual uint32_t GetHighIntegerReturnValueRegister();
@@ -16814,7 +16814,7 @@ namespace BinaryNinja {
1681416814
virtual std::vector<uint32_t> GetRegisterArgumentListRegs(uint32_t regListId) override;
1681516815
virtual BNRegisterListKind GetRegisterArgumentListKind(uint32_t regListId) override;
1681616816
virtual std::vector<Variable> GetVariablesForParameters(const std::vector<FunctionParameter>& paramTypes,
16817-
const std::set<uint32_t>* permittedRegs = nullptr) override;
16817+
const std::optional<std::set<uint32_t>>& permittedRegs = std::nullopt) override;
1681816818
};
1681916819

1682016820
/*!

callingconvention.cpp

Lines changed: 172 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -298,29 +298,185 @@ vector<uint32_t> CallingConvention::GetFloatArgumentRegisters()
298298

299299
vector<uint32_t> CallingConvention::GetRegisterArgumentClasses()
300300
{
301-
return vector<uint32_t>();
301+
/*
302+
This should return vector<uint32_t> {} when all architecture
303+
supports register class and register list.
304+
*/
305+
if (AreArgumentRegistersSharedIndex())
306+
return vector<uint32_t> {0};
307+
308+
return vector<uint32_t> {0, 1};
302309
}
303310

304311

305312
vector<uint32_t> CallingConvention::GetRegisterArgumentClassLists(uint32_t classId)
306313
{
307-
return vector<uint32_t>();
314+
/*
315+
This should return vector<uint32_t> {} when all architecture
316+
supports register class and register list.
317+
*/
318+
if (AreArgumentRegistersSharedIndex()) {
319+
return vector<uint32_t> {0, 1};
320+
} else {
321+
if (0 == classId) {
322+
return vector<uint32_t> {0};
323+
} else if (1 == classId) {
324+
return vector<uint32_t> {1};
325+
}
326+
}
327+
return vector<uint32_t> {};
308328
}
309329

310330

311331
vector<uint32_t> CallingConvention::GetRegisterArgumentLists()
312332
{
313-
// Default implementation: derive from classes
314-
return vector<uint32_t>();
333+
vector<uint32_t> result;
334+
vector<uint32_t> classes = GetRegisterArgumentClasses();
335+
for(uint32_t classId : classes)
336+
{
337+
vector<uint32_t> lists = GetRegisterArgumentClassLists(classId);
338+
result.insert(result.end(), lists.begin(), lists.end());
339+
}
340+
return result;
315341
}
316342

317343

318344
vector<uint32_t> CallingConvention::GetRegisterArgumentListRegs(uint32_t regListId)
319345
{
320-
// Default implementation: no registers for any list
346+
/*
347+
This should return vector<uint32_t> {} when all architecture
348+
supports register class and register list.
349+
350+
Bridge implementation: use old APIs as fallback for architectures that haven't
351+
implemented the new register list/class APIs yet
352+
*/
353+
if (regListId == 0) {
354+
return GetIntegerArgumentRegisters();
355+
} else if (regListId == 1) {
356+
return GetFloatArgumentRegisters();
357+
}
321358
return vector<uint32_t>();
322359
}
323360

361+
vector<Variable> CallingConvention::GetVariablesForParameters(
362+
const vector<FunctionParameter>& params, const std::optional<set<uint32_t>>& permittedRegs)
363+
{
364+
vector<uint32_t> intArgs = GetIntegerArgumentRegisters();
365+
vector<uint32_t> floatArgs = GetFloatArgumentRegisters();
366+
367+
vector<Variable> result;
368+
auto intArgIter = intArgs.begin();
369+
auto floatArgIter = floatArgs.begin();
370+
size_t addrSize = GetArchitecture()->GetAddressSize();
371+
int64_t stackOffset = 0;
372+
bool sharedIndex = AreArgumentRegistersSharedIndex();
373+
if (GetArchitecture()->GetLinkRegister() == BN_INVALID_REGISTER)
374+
stackOffset = addrSize;
375+
if (IsStackReservedForArgumentRegisters())
376+
stackOffset += intArgs.size() * addrSize;
377+
378+
379+
// TODO: Structure in register and multi-reg parameters
380+
for (auto& param : params)
381+
{
382+
size_t width = param.type->GetWidth();
383+
384+
if (!param.defaultLocation)
385+
{
386+
// Parameter not storage in a normal location, use custom variable
387+
result.push_back(param.location);
388+
if (param.location.type == RegisterVariableSourceType)
389+
{
390+
// If non-default location matches the next register in the register parameter
391+
// lists, advance the iterators. It may just be a type mismatch, and we still
392+
// want to maintain the state for future parameters.
393+
if (intArgIter != intArgs.end() && *intArgIter == param.location.storage)
394+
{
395+
intArgIter++;
396+
if (sharedIndex && floatArgIter != floatArgs.end())
397+
floatArgIter++;
398+
}
399+
else if (floatArgIter != floatArgs.end() && *floatArgIter == param.location.storage)
400+
{
401+
floatArgIter++;
402+
if (sharedIndex && intArgIter != intArgs.end())
403+
intArgIter++;
404+
}
405+
}
406+
else if (param.location.type == StackVariableSourceType)
407+
{
408+
// Adjust next automatic stack location to after this one
409+
stackOffset = param.location.storage;
410+
if (width < addrSize)
411+
width = addrSize;
412+
else if ((width % addrSize) != 0)
413+
width += addrSize - (width % addrSize);
414+
stackOffset += width;
415+
}
416+
continue;
417+
}
418+
419+
if (param.type->IsFloat())
420+
{
421+
if (permittedRegs.has_value() && floatArgIter != floatArgs.end()
422+
&& permittedRegs.value().count(*floatArgIter) == 0)
423+
{
424+
// Disallowed register parameter, start spilling to stack. This is used in calling
425+
// conventions that place all variable argument parameters on the stack.
426+
floatArgIter = floatArgs.end();
427+
if (sharedIndex)
428+
intArgIter = intArgs.end();
429+
}
430+
else if (floatArgIter != floatArgs.end())
431+
{
432+
BNRegisterInfo regInfo = GetArchitecture()->GetRegisterInfo(*floatArgIter);
433+
if (width <= regInfo.size)
434+
{
435+
result.emplace_back(RegisterVariableSourceType, 0, *floatArgIter);
436+
floatArgIter++;
437+
if (sharedIndex && intArgIter != intArgs.end())
438+
intArgIter++;
439+
continue;
440+
}
441+
}
442+
}
443+
else
444+
{
445+
if (permittedRegs.has_value() && intArgIter != intArgs.end()
446+
&& permittedRegs.value().count(*intArgIter) == 0)
447+
{
448+
// Disallowed register parameter, start spilling to stack. This is used in calling
449+
// conventions that place all variable argument parameters on the stack.
450+
intArgIter = intArgs.end();
451+
if (sharedIndex)
452+
floatArgIter = floatArgs.end();
453+
}
454+
else if (intArgIter != intArgs.end())
455+
{
456+
BNRegisterInfo regInfo = GetArchitecture()->GetRegisterInfo(*intArgIter);
457+
if (width <= regInfo.size)
458+
{
459+
result.emplace_back(RegisterVariableSourceType, 0, *intArgIter);
460+
intArgIter++;
461+
if (sharedIndex && floatArgIter != floatArgs.end())
462+
floatArgIter++;
463+
continue;
464+
}
465+
}
466+
}
467+
468+
result.emplace_back(StackVariableSourceType, 0, stackOffset);
469+
470+
if (width < addrSize)
471+
width = addrSize;
472+
else if ((width % addrSize) != 0)
473+
width += addrSize - (width % addrSize);
474+
stackOffset += width;
475+
}
476+
477+
return result;
478+
}
479+
324480

325481
BNRegisterListKind CallingConvention::GetRegisterArgumentListKind(uint32_t regListId)
326482
{
@@ -329,12 +485,6 @@ BNRegisterListKind CallingConvention::GetRegisterArgumentListKind(uint32_t regLi
329485
}
330486

331487

332-
vector<Variable> CallingConvention::GetVariablesForParameters(const vector<FunctionParameter>& paramTypes,
333-
const std::set<uint32_t>* permittedRegs)
334-
{
335-
return vector<Variable>();
336-
}
337-
338488
bool CallingConvention::AreArgumentRegistersSharedIndex()
339489
{
340490
return false;
@@ -608,7 +758,7 @@ BNRegisterListKind CoreCallingConvention::GetRegisterArgumentListKind(uint32_t r
608758

609759

610760
vector<Variable> CoreCallingConvention::GetVariablesForParameters(const vector<FunctionParameter>& paramTypes,
611-
const std::set<uint32_t>* permittedRegs)
761+
const std::optional<std::set<uint32_t>>& permittedRegs)
612762
{
613763
BNFunctionParameter* params = new BNFunctionParameter[paramTypes.size()];
614764
for (size_t i = 0; i < paramTypes.size(); i++)
@@ -624,12 +774,12 @@ vector<Variable> CoreCallingConvention::GetVariablesForParameters(const vector<F
624774

625775
uint32_t* permittedRegsArray = nullptr;
626776
size_t permittedRegsCount = 0;
627-
if (permittedRegs != nullptr)
777+
if (permittedRegs.has_value())
628778
{
629-
permittedRegsCount = permittedRegs->size();
779+
permittedRegsCount = permittedRegs.value().size();
630780
permittedRegsArray = new uint32_t[permittedRegsCount];
631781
size_t j = 0;
632-
for (auto reg : *permittedRegs)
782+
for (auto reg : permittedRegs.value())
633783
permittedRegsArray[j++] = reg;
634784
}
635785

@@ -640,11 +790,11 @@ vector<Variable> CoreCallingConvention::GetVariablesForParameters(const vector<F
640790
vector<Variable> result;
641791
for (size_t i = 0; i < count; i++)
642792
result.push_back(vars[i]);
643-
793+
BNFreeVariableList(vars);
794+
644795
delete[] params;
645796
if (permittedRegsArray)
646797
delete[] permittedRegsArray;
647-
BNFreeVariableList(vars);
648798
return result;
649799
}
650800

@@ -723,34 +873,21 @@ BNVariable* CallingConvention::GetVariablesForParametersCallback(void* ctxt, con
723873
params.push_back(param);
724874
}
725875

726-
std::set<uint32_t>* permittedRegsSet = nullptr;
876+
std::set<uint32_t> regsSet;
877+
std::optional<std::set<uint32_t>> permittedRegsSet;
727878
if (permittedRegs && permittedRegCount > 0)
728879
{
729-
permittedRegsSet = new std::set<uint32_t>();
730880
for (size_t i = 0; i < permittedRegCount; i++)
731-
permittedRegsSet->insert(permittedRegs[i]);
732-
}
733-
734-
vector<Variable> variables = cc->GetVariablesForParameters(params, permittedRegsSet);
735-
736-
// If the calling convention doesn't implement this method, it returns an empty vector
737-
// Signal fallback to core implementation by returning NULL with count 0
738-
if (variables.empty())
739-
{
740-
*resultCount = 0;
741-
if (permittedRegsSet)
742-
delete permittedRegsSet;
743-
return nullptr;
881+
regsSet.insert(permittedRegs[i]);
882+
permittedRegsSet = regsSet;
744883
}
745884

885+
vector<Variable> variables = cc->GetVariablesForParameters(params, permittedRegsSet);
746886
*resultCount = variables.size();
747887

748888
BNVariable* result = new BNVariable[variables.size()];
749889
for (size_t i = 0; i < variables.size(); i++)
750890
result[i] = variables[i];
751891

752-
if (permittedRegsSet)
753-
delete permittedRegsSet;
754-
755892
return result;
756893
}

0 commit comments

Comments
 (0)