{"id":4035,"date":"2019-11-15T08:03:36","date_gmt":"2019-11-15T08:03:36","guid":{"rendered":"http:\/\/mertboru.com\/?p=4035"},"modified":"2020-07-27T07:46:14","modified_gmt":"2020-07-27T07:46:14","slug":"demystifying-vmt-and-rtti-in-unreal-engine-c","status":"publish","type":"post","link":"http:\/\/mertboru.com\/?p=4035","title":{"rendered":"Demystifying VMT and RTTI in Unreal Engine C++"},"content":{"rendered":"<p style=\"text-align: right;\"><span style=\"color: #999999;\"><em>(Cover Photo: \u00a91984 &#8211; ITV Granada<\/em><\/span><br \/>\n<span style=\"color: #999999;\"><em>Jeremy Brett, &#8220;Sherlock Holmes&#8221; TV Series<\/em><\/span><span style=\"color: #999999;\"><em>)<\/em><\/span><\/p>\n<p><strong>It is no secret that, due to nature of modern OOP guidelines, Unreal Engine C++ source code is full of <em>\u201cvirtual functions\u201d<\/em>. It is <em>also<\/em> no secret that, calling a virtual function is inherently slower than calling a non-virtual function&#8230; So, what&#8217;s the catch?<\/strong><\/p>\n<p>A <span style=\"color: #800000;\"><em><strong>non-virtual call<\/strong><\/em><\/span> is simply a jump (JMP) to a compiled-in pointer. On the other hand, a <span style=\"color: #800000;\"><em><strong>virtual call<\/strong><\/em><\/span> requires at least an extra indexed dereference, and sometimes a fixup addition, which is stored in a lookup table known as <strong>Virtual Method Table (VMT)<\/strong>. This is simply why a virtual call is always slower than a non-virtual call.<\/p>\n<p>To avoid this overhead, compilers usually steer clear of VMT whenever the call can be resolved at compile time. However, due to complex nature of <strong>Inheritence<\/strong> based class structures used in modern game engines, using VMT is unavoidable in most cases.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-4081 size-full aligncenter\" src=\"http:\/\/mertboru.com\/wp-content\/uploads\/2019\/11\/z.webbullet_h77_endof.png\" alt=\"\" width=\"27\" height=\"77\" \/><\/p>\n<p><strong>Virtual Method Table (VMT)<\/strong><\/p>\n<p>An object&#8217;s <strong>VMT<\/strong> (also known as <em><strong>vtable<\/strong>)<\/em> contains the addresses of the object&#8217;s dynamically bound methods. Method calls are performed by fetching the method&#8217;s address from the object&#8217;s virtual method table.<\/p>\n<p>C++ compiler creates a separate VMT for each class. When an object is created, a virtual pointer <strong>(VPTR)<\/strong> to this table is added as a hidden member of this object. The compiler also generates <span style=\"color: #800000;\"><em><strong>hidden code<\/strong><\/em><\/span> in the constructors of each class to initialize new object&#8217;s VPTR to the address of its class&#8217; virtual method table.<\/p>\n<p>The virtual method table is same for all objects belonging to the same class, and is therefore typically shared between them. Objects belonging to type-compatible classes in an inheritance hierarchy will have virtual method tables with the same layout.<\/p>\n<div style=\"border: 1px solid red; padding: 25px; margin: 25px;\"><strong>Tip:<\/strong> The C++ standards do <span style=\"color: #800000;\"><em><strong>not<\/strong><\/em><\/span> mandate exactly how dynamic dispatch must be implemented, but compilers generally use minor variations on the same basic model. The VMT is generally a good performance trade-off to achieve dynamic dispatch, but there are alternatives, such as <strong>Binary Tree Dispatch (BTD)<\/strong>, with higher performance but different costs.<\/div>\n<p>Speaking of hidden codes and VMTs in the constructors of each class, each C++ object should also contain additional information about its <span style=\"color: #800000;\"><em><strong>type<\/strong><\/em><\/span>. An object&#8217;s data type is a crucial information in terms of <em><span style=\"color: #800000;\"><strong>casting<\/strong><\/span><\/em>.<\/p>\n<p><strong><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-4081 size-full aligncenter\" src=\"http:\/\/mertboru.com\/wp-content\/uploads\/2019\/11\/z.webbullet_h77_endof.png\" alt=\"\" width=\"27\" height=\"77\" \/><\/strong><\/p>\n<p><strong>Run-Time Type Information\u00a0 (RTTI)<\/strong><\/p>\n<p>RTTI is a feature of the C++ programming language that exposes information about an object&#8217;s data type at runtime. It can apply to simple data types, such as integers and characters, or to generic types.<\/p>\n<p>Run-Time Type Information\u00a0is available only for classes that are <strong>polymorphic<\/strong>, which means they have <em><span style=\"color: #800000;\"><strong>at least one virtual method<\/strong><\/span><\/em>. In practice, this is <strong>not<\/strong> a limitation because base classes must have a virtual destructor to allow objects of derived classes to perform proper cleanup if they are deleted from a base pointer.<\/p>\n<p>RTTI is used in three main C++ language elements:<\/p>\n<p style=\"padding-left: 40px;\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1650\" src=\"http:\/\/mertboru.com\/wp-content\/uploads\/2015\/03\/z.webbullet_dashed.png\" alt=\"\" width=\"11\" height=\"11\" \/>\u00a0 The <em><strong>dynamic_cast<\/strong><\/em> operator: Used for conversion of polymorphic types.<\/p>\n<p style=\"padding-left: 40px;\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1650\" src=\"http:\/\/mertboru.com\/wp-content\/uploads\/2015\/03\/z.webbullet_dashed.png\" alt=\"\" width=\"11\" height=\"11\" \/>\u00a0 The <em><strong>typeid<\/strong> <\/em>operator: Used for identifying the exact type of an object.<\/p>\n<p style=\"padding-left: 40px;\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1650\" src=\"http:\/\/mertboru.com\/wp-content\/uploads\/2015\/03\/z.webbullet_dashed.png\" alt=\"\" width=\"11\" height=\"11\" \/>\u00a0 The <em><strong>type_info<\/strong><\/em> class: Used to hold the type information returned by the typeid operator.<\/p>\n<p>In order to perform cast-related operations listed above, RTTI heavily uses <strong>VMT<\/strong>. For example, given an object of a polymorphic class, a <em><strong>type_info<\/strong><\/em> object can be obtained through the use of the <em><strong>typeid<\/strong><\/em> operator.\u00a0 In principle, this is a simple operation which involves finding the <strong>VMT<\/strong>, through that finding the most-derived class object of which the object is part, and then extracting a pointer to the <em><strong>type_info<\/strong><\/em> object from that object\u2019s virtual function table (or equivalent).<\/p>\n<p>In terms of performance, using the <em><strong>dynamic_cast<\/strong><\/em> operator is more expensive than <em><strong>type_info<\/strong><\/em>. Given a pointer to an object of a polymorphic class, a cast to a pointer to another base subobject of the same derived class object can be done using a <em><strong>dynamic_cast<\/strong><\/em>.\u00a0 In principle, this operation involves finding the <strong>VMT<\/strong>, through that finding the most-derived class object of which the object is part, and then using type information associated with that object to determine if the conversion (cast) is allowed, and finally performing any required adjustments of the pointer.\u00a0 In principle, this checking involves the traversal of a data structure describing the base classes of the most derived class.\u00a0 Thus, the run-time cost of a <em><strong>dynamic_cast<\/strong><\/em> may depend on the relative positions in the class hierarchy of the two classes involved.<\/p>\n<div style=\"border: 1px solid red; padding: 25px; margin: 25px;\"><strong>Tip:<\/strong> In the original C++ design, Bjarne Stroustrup did not include RTTI, because he thought this mechanism was often misused.<\/div>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-4081 size-full\" src=\"http:\/\/mertboru.com\/wp-content\/uploads\/2019\/11\/z.webbullet_h77_endof.png\" alt=\"\" width=\"27\" height=\"77\" \/><\/p>\n<p><strong>Hacking VMT and RTTI Information using UE C++<\/strong><\/p>\n<p>In order to gather <span style=\"color: #800000;\"><em><strong>&#8220;header&#8221;<\/strong><\/em><\/span> information (that contains VMT and RTTI data) in an Unreal Engine C++ class\/object, I have written the following <strong>LogClassHeader()<\/strong> C++ function using Visual Studio 2019 version 16.3.8 for Unreal Engine version 4.23.1.<\/p>\n<pre style=\"font-size: 12px;\"><span style=\"color: #00ccff;\"><strong><span style=\"color: #008080;\">void<\/span><\/strong> UDebugCore<\/span>::<strong>LogClassHeader<\/strong>(<strong><span style=\"color: #008080;\">void<\/span><\/strong>* <strong><span style=\"color: #008080;\">const<\/span><\/strong> pThis, <strong><em><span style=\"color: #00ccff;\">size_t<\/span><\/em><\/strong> nSize)\r\n{\r\n  <strong><em><span style=\"color: #00ccff;\">FString<\/span><\/em><\/strong> fsClassName = \"NULL\";\r\n  <strong><em><span style=\"color: #00ccff;\">FString<\/span><\/em><\/strong> fsObjectName = \"NULL\";\r\n  <strong><em><span style=\"color: #00ccff;\">UObject<\/span><\/em><\/strong>* <span style=\"color: #008000;\"><strong>const<\/strong><\/span> pCastedToUObject = (<strong><em><span style=\"color: #00ccff;\">UObject<\/span><\/em><\/strong>*)(pThis);\r\n  <strong><span style=\"color: #008080;\">void<\/span><\/strong>** <strong><span style=\"color: #008080;\">const<\/span><\/strong> pCastedToHeader = <strong><span style=\"color: #008080;\">reinterpret_cast<\/span><\/strong>&lt;<strong><span style=\"color: #008080;\">void<\/span><\/strong>**&gt;(pThis);\r\n\r\n  <strong><span style=\"color: #800000;\">if<\/span><\/strong> (pCastedToUObject)\r\n  {\r\n    fsClassName = pCastedToUObject-&gt;<em>GetClass<\/em>()-&gt;<em>GetName<\/em>();\r\n    fsObjectName = pCastedToUObject-&gt;<em>GetName<\/em>();\r\n  }\r\n\r\n  <strong><span style=\"color: #800000;\">if<\/span><\/strong> (pCastedToHeader)\r\n  {\r\n    <strong><span style=\"color: #800000;\">for<\/span><\/strong> (<strong><em><span style=\"color: #00ccff;\">size_t<\/span><\/em><\/strong> i = 0; i &lt; nSize \/ <strong><span style=\"color: #008080;\">sizeof<\/span><\/strong>(<strong><span style=\"color: #008080;\">void<\/span><\/strong>*); i++)\r\n    {\r\n      <strong><span style=\"color: #800000;\">MACRO_PRINTF<\/span><\/strong>(\"Pointer[%04zu] = 0x%p\", i, pCastedToHeader[i])\r\n    }\r\n  }\r\n}<\/pre>\n<p>This function has 2 input parameters:<\/p>\n<p style=\"padding-left: 40px;\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1650\" src=\"http:\/\/mertboru.com\/wp-content\/uploads\/2015\/03\/z.webbullet_dashed.png\" alt=\"\" width=\"11\" height=\"11\" \/>\u00a0 <strong>pThis:\u00a0<\/strong> <em>Object to extract Class Header Info from<\/em><br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1650\" src=\"http:\/\/mertboru.com\/wp-content\/uploads\/2015\/03\/z.webbullet_dashed.png\" alt=\"\" width=\"11\" height=\"11\" \/>\u00a0 <strong>nSize:<\/strong>\u00a0 <em>Size of Header<\/em><\/p>\n<p>Calling the function is very easy. You simply insert your call into the constructor of the class that you would like to hack. For example, the following code gathers C++ header information of <strong>&lt;APlayerControllerThirdPerson&gt;<\/strong> class.<\/p>\n<pre style=\"font-size: 12px;\"><span style=\"color: #00ccff;\">APlayerControllerThirdPerson<\/span>::<span style=\"color: #00ccff;\">APlayerControllerThirdPerson<\/span>()\r\n{\r\n  <span style=\"color: #00ccff;\">UDebugCore<\/span>::<strong>LogClassHeader<\/strong>(<strong><span style=\"color: #008080;\">this<\/span><\/strong>, <strong><span style=\"color: #008080;\">sizeof<\/span><\/strong>(*<strong><span style=\"color: #008080;\">this<\/span><\/strong>));\r\n}<\/pre>\n<p>When you run the code, all pointers that are available (and used) in the header of &lt;APlayerControllerThirdPerson&gt; will be listed. And, in case you need, <strong>instance name<\/strong> and <strong>class type<\/strong> is stored in <em>fsObjectName<\/em> and <em>fsClassName<\/em> variables, as a bonus.<\/p>\n<pre style=\"font-size: 12px;\">Pointer[0000] = 0x00007FFC8A3ECB00\r\nPointer[0001] = 0x0000BC5B00000231\r\nPointer[0002] = 0x000001648346AC00\r\nPointer[0003] = 0x000AAD5B000AAD5B\r\nPointer[0004] = 0x0000000000000000\r\nPointer[0005] = 0x00000164834864E0\r\nPointer[0006] = 0x00007FFCAAB2EF98\r\nPointer[0007] = 0x00007FFCA8708208\r\nPointer[0008] = 0x0000000F00000000\r\n            .....\r\n             ...\r\n              .<\/pre>\n<p>So, what do these numbers mean? Well, all these pointers are addresses of the virtual functions, followed by some of the member variables. In order to understand which is which, we need to decipher the structure of the data set.<\/p>\n<p>Here comes the tricky part! With each and every update to Visual Studio C++ compiler, the structure tends to get updated as well. In other words, the header structure of a C++ class changes with each major compiler update. Try to think of it as a <strong><em>&#8220;living organism&#8221;<\/em><\/strong>. As I&#8217;m typing this sentence now, a new update with a new C++ header structure may be on its way. So, it is up to you (!) to <span style=\"color: #800000;\"><em><strong>analyze<\/strong><\/em><\/span> what&#8217;s going on under the hood.<\/p>\n<p>Good news is, we can gather &lt;template&gt; information about C++ class header structure from the official <strong>Microsoft patent documents<\/strong>! Although they are not up-to-date, I think it is a good practice to start the investigation using the source of information itself.<\/p>\n<p>Here is some of the Microsoft patents which describe various parts of C++ implementation used in Visual Studio:<\/p>\n<p style=\"padding-left: 40px;\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1650\" src=\"http:\/\/mertboru.com\/wp-content\/uploads\/2015\/03\/z.webbullet_dashed.png\" alt=\"\" width=\"11\" height=\"11\" \/>\u00a0 <strong>US Patent <a href=\"http:\/\/www.freepatentsonline.com\/5410705.pdf\" target=\"_blank\" rel=\"noopener noreferrer\">#5410705<\/a>:<\/strong> <em>\u201cMethod for generating an object data structure layout for a class in a compiler for an object-oriented programming language\u201d<\/em><\/p>\n<p style=\"padding-left: 40px;\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1650\" src=\"http:\/\/mertboru.com\/wp-content\/uploads\/2015\/03\/z.webbullet_dashed.png\" alt=\"\" width=\"11\" height=\"11\" \/>\u00a0 <strong>US Patent <a href=\"http:\/\/www.freepatentsonline.com\/5617569.pdf\" target=\"_blank\" rel=\"noopener noreferrer\">#5617569<\/a>:<\/strong> <em>\u201cMethod and system for implementing pointers to members in a compiler for an object-oriented programming language\u201d<\/em><\/p>\n<p style=\"padding-left: 40px;\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1650\" src=\"http:\/\/mertboru.com\/wp-content\/uploads\/2015\/03\/z.webbullet_dashed.png\" alt=\"\" width=\"11\" height=\"11\" \/>\u00a0 <strong>US Patent <a href=\"http:\/\/www.freepatentsonline.com\/5754862.pdf\" target=\"_blank\" rel=\"noopener noreferrer\">#5754862<\/a>:<\/strong> <em>\u201cMethod and system for accessing virtual base classes\u201d<\/em><\/p>\n<p style=\"padding-left: 40px;\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1650\" src=\"http:\/\/mertboru.com\/wp-content\/uploads\/2015\/03\/z.webbullet_dashed.png\" alt=\"\" width=\"11\" height=\"11\" \/>\u00a0 <strong>US Patent <a href=\"http:\/\/www.freepatentsonline.com\/5297284.pdf\" target=\"_blank\" rel=\"noopener noreferrer\">#5297284<\/a>:<\/strong> <em>\u201cMethod and system for implementing virtual functions and virtual base classes and setting a this pointer for an object-oriented programming language\u201d<\/em><\/p>\n<p style=\"padding-left: 40px;\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1650\" src=\"http:\/\/mertboru.com\/wp-content\/uploads\/2015\/03\/z.webbullet_dashed.png\" alt=\"\" width=\"11\" height=\"11\" \/>\u00a0 <strong>US Patent <a href=\"http:\/\/www.freepatentsonline.com\/5371891.pdf\" target=\"_blank\" rel=\"noopener noreferrer\">#5371891<\/a>:<\/strong> <em>\u201cMethod for object construction in a compiler for an object-oriented programming language\u201d<\/em><\/p>\n<p style=\"padding-left: 40px;\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1650\" src=\"http:\/\/mertboru.com\/wp-content\/uploads\/2015\/03\/z.webbullet_dashed.png\" alt=\"\" width=\"11\" height=\"11\" \/>\u00a0 <strong>US Patent <a href=\"http:\/\/www.freepatentsonline.com\/5603030.pdf\" target=\"_blank\" rel=\"noopener noreferrer\">#5603030<\/a>:<\/strong> <em>\u201cMethod and system for destruction of objects using multiple destructor functions in an object-oriented computer system\u201d<\/em><\/p>\n<p>So, what I&#8217;m offering is, good old-fashioned <span style=\"color: #800000;\"><strong>\u201c<em>reverse engineering\u201d<\/em><\/strong><\/span>.<\/p>\n<p style=\"padding-left: 40px;\"><em>&#8211; &#8220;Is such a challenge worth it?&#8221;<\/em><\/p>\n<p style=\"padding-left: 40px;\"><em>&#8211; &#8220;Um, yes!&#8230; If it doesn&#8217;t break you, it can <strong>make<\/strong> you.&#8221;<\/em><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-4081 size-full aligncenter\" src=\"http:\/\/mertboru.com\/wp-content\/uploads\/2019\/11\/z.webbullet_h77_endof.png\" alt=\"\" width=\"27\" height=\"77\" \/><\/p>\n<p><strong>References:<\/strong><\/p>\n<p style=\"padding-left: 40px;\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1650\" src=\"http:\/\/mertboru.com\/wp-content\/uploads\/2015\/03\/z.webbullet_dashed.png\" alt=\"\" width=\"11\" height=\"11\" \/>\u00a0 Bjarne Stroustrup, \u201c<em>A History of C++: 1979\u20141991\u201d<\/em>, p. 50 \u2013 (March 1993)<\/p>\n<p style=\"padding-left: 40px;\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1650\" src=\"http:\/\/mertboru.com\/wp-content\/uploads\/2015\/03\/z.webbullet_dashed.png\" alt=\"\" width=\"11\" height=\"11\" \/>\u00a0 Keith Cooper &amp; Linda Torczon, <em>\u201cEngineering A Compiler\u201d<\/em>, Morgan Kaufmann, 2nd Edition \u2013 (2011)<\/p>\n<p style=\"padding-left: 40px;\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1650\" src=\"http:\/\/mertboru.com\/wp-content\/uploads\/2015\/03\/z.webbullet_dashed.png\" alt=\"\" width=\"11\" height=\"11\" \/>\u00a0 Microsoft Visual Studio Documentation, \u201c<em>C++ Run-Time Type Information\u201d<\/em> &#8211; (November 2016)<\/p>\n<p style=\"padding-left: 40px;\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1650\" src=\"http:\/\/mertboru.com\/wp-content\/uploads\/2015\/03\/z.webbullet_dashed.png\" alt=\"\" width=\"11\" height=\"11\" \/>\u00a0 <em>\u201cTechnical Report on C++ Performance\u201d<\/em>, OpenRCE.org \u2013 (September 2006)<\/p>\n<p style=\"padding-left: 40px;\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1650\" src=\"http:\/\/mertboru.com\/wp-content\/uploads\/2015\/03\/z.webbullet_dashed.png\" alt=\"\" width=\"11\" height=\"11\" \/>\u00a0 <em>\u201cReversing Microsoft Visual C++: Classes, Methods and RTTI\u201d<\/em>, OpenRCE.org \u2013 (September 2006)<\/p>\n<p style=\"padding-left: 40px;\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1650\" src=\"http:\/\/mertboru.com\/wp-content\/uploads\/2015\/03\/z.webbullet_dashed.png\" alt=\"\" width=\"11\" height=\"11\" \/>\u00a0 <em>\u201cIntel\u00ae 64 and IA-32 Architectures Optimization Reference Manual\u201d<\/em> \u2013 (April 2018)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>(Cover Photo: \u00a91984 &#8211; ITV Granada Jeremy Brett, &#8220;Sherlock Holmes&#8221; TV Series) It is no secret that, due to nature of modern OOP guidelines, Unreal Engine C++ source code is full of \u201cvirtual functions\u201d. It is also no secret that, calling a virtual function is inherently slower than calling a non-virtual function&#8230; So, what&#8217;s the &hellip; <a href=\"http:\/\/mertboru.com\/?p=4035\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Demystifying VMT and RTTI in Unreal Engine C++<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":6648,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26,7],"tags":[175,233,231,230,232,227,226,234,235,44,229,223,224,228,225],"class_list":["post-4035","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-articles","category-gamedev","tag-c-c","tag-dynamic_cast","tag-inheritence","tag-non-virtual-call","tag-polymorphic","tag-rtti","tag-run-time-type-information","tag-typeid","tag-type_info","tag-unreal-engine","tag-virtual-call","tag-virtual-method-table","tag-vmt","tag-vptr","tag-vtable"],"_links":{"self":[{"href":"http:\/\/mertboru.com\/index.php?rest_route=\/wp\/v2\/posts\/4035","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/mertboru.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/mertboru.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/mertboru.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/mertboru.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=4035"}],"version-history":[{"count":1,"href":"http:\/\/mertboru.com\/index.php?rest_route=\/wp\/v2\/posts\/4035\/revisions"}],"predecessor-version":[{"id":6649,"href":"http:\/\/mertboru.com\/index.php?rest_route=\/wp\/v2\/posts\/4035\/revisions\/6649"}],"wp:featuredmedia":[{"embeddable":true,"href":"http:\/\/mertboru.com\/index.php?rest_route=\/wp\/v2\/media\/6648"}],"wp:attachment":[{"href":"http:\/\/mertboru.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4035"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/mertboru.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4035"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/mertboru.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4035"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}