前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >CLR跨代(card_table)的一些细节

CLR跨代(card_table)的一些细节

作者头像
江湖评谈
发布2023-10-26 17:57:47
1380
发布2023-10-26 17:57:47
举报
文章被收录于专栏:天下风云天下风云

1.前言 计算里面的0和1是基础中的基础,所以细节非常重要。本篇继续研看下card_table的一些细节。

2.细节一:数组位移 在进行数组操作的时候,根据数组的类型对数组索引进行位移。如下代码:

代码语言:javascript
复制
typedef unsigned int       uint32_t;
int main(int argc,char** argv) {
    uint32_t card_table[] = { 1,3,5,7,9,11,13,15,17 };
    uint32_t* g_card_table = card_table;
    uint32_t bone = g_card_table[2];
}

g_card_table[2]的机器码层面实际上是这样:

代码语言:javascript
复制
00007FF606F05F7B 48 8D 45 08   lea         rax,[card_table]  
00007FF606F05F7F 48 89 45 48    mov         qword ptr [g_card_table],rax  
00007FF606F05F83 B8 04 00 00 00 mov         eax,4  
00007FF606F05F88 48 6B C0 02    imul        rax,rax,2  
00007FF606F05F8C 48 8B 4D 48    mov         rcx,qword ptr [g_card_table]  
00007FF606F05F90 8B 04 01       mov         eax,dword ptr [rcx+rax]  
00007FF606F05F93 89 45 64       mov         dword ptr [bone],eax

以上代码在Linux下面可能是这样:

代码语言:javascript
复制
Windows:00007FF606F05F88 48 6B C0 02 imul  rax,rax,2
Linux  :00007FF606F05F88 48 6B C0 02 shr   rax,2

Windows:
00007FF606F05F8C 48 8B 4D 48 mov  rcx,qword ptr [g_card_table] 
00007FF606F05F90 8B 04 01     mov  eax,dword ptr [rcx+rax]  
Linux:
add eax,[g_card_table+rax]

简单点来说就是:

代码语言:javascript
复制
因为int32_t占四字节,所以
(g_card_table+索引<<2)==bone

也就是说数组里面的索引需要左移,这里应用到card_table,比如:

代码语言:javascript
复制
n1.selfName的地址是:0x00007fbf6a808b08
如果想要取它在card_table里面的0x00007fbf6a808b08>>0xB处索引
就需要把n1.selfName>>8>>5作为card_table索引,也即是:
card_table[n1.selfName>>8>>5];
>>8>>5和0xB相比,多右移了两位,因为数组是int它会自动左移两位。

那么JIT_WriteBarrier_Debug(Debug版本)是如何操作的呢?只需要看下面这部分代码即可

代码语言:javascript
复制
  0x7ffff730f72e <+78>:  movabs rax, 0x7faedb5ff040
   0x7ffff730f738 <+88>:  mov    ecx, r8d
   0x7ffff730f73b <+91>:  shr    r8, 0xb
   0x7ffff730f73f <+95>:  shr    ecx, 0x8
   0x7ffff730f742 <+98>:  and    ecx, 0x7
   0x7ffff730f745 <+101>: mov    dl, 0x1
   0x7ffff730f747 <+103>: shl    dl, cl
   0x7ffff730f749 <+105>: test   byte ptr [r8 + rax], dl
   0x7ffff730f74d <+109>: je     0x7ffff730f751            ; <+113>
   0x7ffff730f74f <+111>: rep    ret
   0x7ffff730f751 <+113>: lock   
   0x7ffff730f752 <+114>: or     byte ptr [r8 + rax], dl

意思是:

代码语言:javascript
复制
(card_table(rax)+n1.selfName>>0xB) || 1<<3

取值呢?find_card里面

代码语言:javascript
复制
last_card_word = &card_table [card_word (card)];

card的值是n1.selfName/256(2的八次方),card_word是在card基础上再除以32(2的五次方),结果就是除以0xD,因为是int数组操作所以需左移2位,card_table的索引即是n1.selfName/0xB.跟上面JIT_WriteBarrier_Debug符合。

3.细节二:card_table范围查找 linux下面一个card覆盖了2的8次方也即是256个字节的范围,一个card_word则覆盖了2的13次方,也即是8192个字节范围。 只要n1.selfName的值在这个范围内即可。在find_card里面find_card_dword找到最后的范围

代码语言:javascript
复制
BOOL gc_heap::find_card(uint32_t* card_table,
                        size_t&   card,
                        size_t    card_word_end,
                        size_t&   end_card)
{
        size_t lcw = card_word(card) + (bit_position != 0);
        if (gc_heap::find_card_dword (lcw, card_word_end) == FALSE)
        {
            return FALSE;
        }
        else
        {
            last_card_word = &card_table [lcw];
            card_word_value = *last_card_word;
        }
        bit_position = 0;
}

这个计算出来的结果last_card_word,覆盖的8192个字节范围包含了n1.selfName对象的地址,那么mark_through_cards_for_segments里面的变量o和limit循环这个范围,找出n1.selfName引用的n2,对其进行标记。

4.细节三:CARD_BUNDLE 这个标志,应该是在8192位一个单位,再次进行标记。以缩小范围的查找。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-10-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 江湖评谈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档