How to add new attributes and propagate it using LLVM?
How about attributes in assembly language?
References:
An attribute can be a single “enum” value (the enum being the [Attribute::AttrKind] enum), a string representing a target-dependent attribute, or an attribute-value pair. Some examples:
Note: for an attribute value pair, we expect a target-dependent attribute to have a string for the value.
An Attribute object is passed by value.
[Attribute::get] to create a new Attribute object
[Attribute::AttrKind] enum. This enumeration lists the attributes that can be associated with parameters, function results, or the function itself.
llvm/IR/Attributes.inc
stores a collection of Attribute objects for each kind of object that may have an attribute associated with it:
A function’s attributes are at index AttributeList::FunctionIndex
;
the return type’s attributes are at index AttributeList::ReturnIndex
;
the function’s parameters’ attributes are at indices 1, …, n (where ‘n’ is the number of parameters). Most methods on the AttributeList class take an index parameter.
A builder class to create AttributeList object;
add and remove attributes;
An AttrBuilder should be passed by reference.
DO NOT USE AttrBuilder::addRawValue()
, or AttrBuilder(uint64_t Val)
; will be remove in the future.
Parsed representation of an attribute is an ‘PassedAttr’ object.
keywords attribute vs non-keywords attribute.
Sema::ProcessDeclAttributeList()
is called with Decl
and an ParsedAttr
, transform a parsed attribute into a semantic attribute. The semantic attribute object is attached to Decl
, can be obtained by Decl::getAttr<T>()
. The process of the attribute is determined by the attribute definition and semantic requirements of the attribute.
Attribute definition in file include/clang/Basic/Attr.td. This definition is used to
To add an attribute:
In include/clang/Basic/Attr.td
, add a new attribute definition. The attribute must derive from an Attr
(tablegen, not semantic) type, or one of its derivatives:
InheritableAttr
: most derive from the InheritableAttr
type; An InheritableAttr specifies that the attribute can be inherited by later redeclarations of the Decl
it is associated with;InheritableParamAttr
is similar to InheritableAttr
, except that the attribute is written on a parameter instead of a declaration;TypeAttr
: the attribute is intended to apply to the type instead of the declarationi; such attribute will generally not be given an AST representation.IgnoredAttr
: parsed but will generate an ignored attribute diagnostic when used; may be useful when an attr is supported by another vendor but not supported by clang.The attr definition contains:
If Args is [StringArgument<"Arg1">, IntArgument<"Arg2">]
, then __attribute__((myattribute("Hello", 3)))
will be a valid use.
Arguments can be flagged optional.
see 1.
getAsString()
, which convert attributes to a string;Attribute::YourAttrbute
in isFunctionOnlyAttr
;ProcessDeclAttribute()
, either by new function or just call handleSimpleAttribute
.clang/lib/CodeGen/CodeGenModule.cpp: attach attribute to function when generate code in CodeGenModule::SetLLVMFunctionAttributesForDefinition()
.
// LLM: privilege tracking attributes for functions
if (D->hasAttr<PrivilegeFunctionAttr>()){
B.addAttribute(llvm::Attribute::PrivilegeFunction);
}
if (D->hasAttr<PrivilegeLevelAttr>()){
B.addAttribute(llvm::Attribute::PrivilegeLevel);
}
Add LLVM support to write/read bitcode with attributes.
case lltok::kw_yourAttribute: B.addAttribute(Attribute::YourAttribute); break;
ATTR_KIND_YourAttribute = 55,
llvm/lib/Bitcode/Writer/BitcodeWriter.cpp:
case Attribute::YourAttribute:
return bitc::ATTR_KIND_YourAttribute;
llvm/include/llvm/Bitcode/BitCodeReader.cpp: in getAttrFromCode:
case bitc::ATTR_KIND_YourAttribute:
return Attribute::YourAttribute;
little change for step 6, change function SetCommonAttributes()
and convert the attribute in clang (attached with clang::GlobalDecal
) to llvm (attached to llvm::GlobalVariable
)
// file: clang/lib/CodeGen/CodeGenModule.cpp
// add priv attribute to global variables
if (llvm::GlobalVariable *GVar= dyn_cast<llvm::GlobalVariable>(GV)){
if (auto *PAttr = D->getAttr<PrivilegeDataAttr>()){
GVar->addAttribute("privilege_data");
}
if ( auto *PAttr = D->getAttr<PrivilegeLevelAttr>()){
GVar->addAttribute("privilege_level", std::to_string(PAttr->getPrivilegeLevel()));
}
}
clang/lib/CodeGen/CGDecl.cpp: EmitParmDecl()
: parse the attribute and add it for bit code code generation.
if (D.hasAttr<PrivilegeDataAttr>()){
llvm::Argument *LLVMArg = dyn_cast<llvm::Argument>(Arg.getAnyValue());
LLVMArg->addAttr(llvm::Attribute::PrivilegeData);
}
llvm/lib/AsmParser/LLParser.cpp: ParseOptionalParamAttrs()
: parse the bit code and convert attribute to LLVM Attribute object. add one line:
case lltok::kw_privilege_data: B.addAttribute(Attribute::PrivilegeData); break;
Clang detected the attribute of local (non-static) variable at clang/lib/CodeGen/CGDecl.cpp: EmitAutoVarAlloca()
;
Clang detected static local variable at clang/lib/CodeGen/CGDecl.cpp: EmitStaticVarDecl()
;
// LLM: add privilege_data attribute
if (auto *PA = D.getAttr<PrivilegeDataAttr>()){
llvm::errs() << "LLM: " << __FILE__ << ":"
<< __FUNCTION__ << ": found priv data attr on static var: "
<< D.getName() << ". Added to llvm::GlobalVariable\n";
var->addAttribute(llvm::Attribute::PrivilegeData);
}
Warning:
/root/cheri/llvm-project/clang/lib/AST/TypePrinter.cpp:1514:11: warning: enumeration values 'PrivilegeData', 'PrivilegeFunction', and 'PrivilegeLevel' not handled in switch [-Wswitch]
switch (T->getAttrKind()) {
solution: added switch cases (commit):
// file: clang/lib/AST/TypePrinter.cpp
// LLM: added to avoid warning
case attr::PrivilegeData:
OS << "privilege_data";
break;
case attr::PrivilegeFunction:
OS << "privilege_function";
break;
case attr::PrivilegeLevel:
OS << "privilege_level(" << "???" << ")";
break;
Warning:
[537/3555] Building CXX object lib/Bitcode/Reader/CMakeFiles/LLVMBitReader.dir/BitcodeReader.cpp.o
/root/cheri/llvm-project/llvm/lib/Bitcode/Reader/BitcodeReader.cpp:1216:11: warning: enumeration values 'PrivilegeData', 'PrivilegeFunction', and 'PrivilegeLevel' not handled in switch [-Wswitch]
switch (Val) {
^
1 warning generated.
[555/3555] Building CXX object lib/Transforms/Utils/CMakeFiles/LLVMTransformUtils.dir/CodeExtractor.cpp.o
/root/cheri/llvm-project/llvm/lib/Transforms/Utils/CodeExtractor.cpp:789:15: warning: enumeration values 'PrivilegeData', 'PrivilegeFunction', and 'PrivilegeLevel' not handled in switch [-Wswitch]
switch (Attr.getKindAsEnum()) {
^
1 warning generated.
If you could revise
the fundmental principles of
computer system design
to improve security...
... what would you change?