在类中,可以使用static关键字修饰成员函数和变量,被修饰后的函数或变量被称为静态成员函数或变量。它们属于整个类,不属于某一个对象,这意味着无需创建对象即可访问静态成员函数或变量。最常见的一个用法就是单例模式(整个类仅可只有一个对象),例:
此处的static主要用于限制修饰对象的作用域。
面向过程中的静态局部变量"只能被初始化一次"是如何实现的?
考虑到静态变量有可能被多次初始化且使用变量初始化,使用的例子如下:
func_a函数中是以常量初始化静态局部变量func_a_value,因此编译器直接将0x1234写入.data对应的位置,这与单(多)线程无关,与单(多)次初始化无关。
若函数以变量形式初始化静态局部变量,则实现初始化一次的原理见静态局部变量res。
存在多个线程初始化res的情况,因此需要进行线程同步。IDA反汇编func_b函数之后的结果如下:
对应的C++代码如下:
_Init_thread_header的源代码如下:
_Init_thread_footer的源代码如下:
从上述代码来看,事情非常明了。pOnce指向的内存初始值为0,通过临界区来实现线程同步,同时只能有一个线程进入到_Init_thread_header和_Init_thread_footer函数。
因为线程是乱序执行的,所以res的结果不是确定的,如下图:
源码的编译环境是Ubuntu 22.04,g++ 11.4.0
同Windows下的常量赋值给静态局部变量,IDA的视图如下:
变量赋值给静态局部变量见"静态局部变量res"章节
IDA反汇编func_b的结果如下:
从该图中可以看出,__cxa_guard_acquire发挥同_Init_thread_header相同的效果,而__cxa_guard_release发挥同_Init_thread_footer相同的效果。这两个函数的源码如下:
__cxa_guard_acquire函数源码
__cxa_guard_release函数源码
像Windows MSVC平台那样分CASE分析,初始状态*g = 0,__gnu_cxx::__is_single_threaded() = true。__gnu_cxx::__is_single_threaded()在pthread_create函数已经被设置为了false,这个操作在执行func_b函数之前。
class
Singleton
{
public
:
static
Singleton& instance()
{
static
Singleton inst;
return
inst;
}
int
& get() {
return
value_; }
private
:
Singleton() : value_(0) { std::cout <<
"Singleton::Singleton()"
<< std::endl; }
Singleton(
const
Singleton&) =
delete
;
Singleton& operator=(
const
Singleton&) =
delete
;
~Singleton() { std::cout <<
"Singleton::~Singleton()"
<< std::endl; }
private
:
int
value_;
};
int
value = Singleton::instance().get()
class
Singleton
{
public
:
static
Singleton& instance()
{
static
Singleton inst;
return
inst;
}
int
& get() {
return
value_; }
private
:
Singleton() : value_(0) { std::cout <<
"Singleton::Singleton()"
<< std::endl; }
Singleton(
const
Singleton&) =
delete
;
Singleton& operator=(
const
Singleton&) =
delete
;
~Singleton() { std::cout <<
"Singleton::~Singleton()"
<< std::endl; }
private
:
int
value_;
};
int
value = Singleton::instance().get()
#include <iostream>
#include <thread>
#include <chrono> // std::chrono::seconds
using
namespace
std;
void
func_a();
void
func_b(
int
a,
int
b);
int
main()
{
func_a();
thread
t1(func_b, 1, 2);
thread
t2(func_b, 3, 4);
thread
t3(func_b, 5, 6);
thread
t4(func_b, 7, 8);
std::this_thread::sleep_for(std::chrono::seconds(1));
getchar
();
t1.join();t2.join();t3.join();t4.join();
return
0;
}
void
func_a()
{
static
int
func_a_value = 0x1234;
cout <<
"func_a_value => "
<< func_a_value <<
", current function = > "
<< __FUNCTION__ << endl;
}
void
func_b(
int
a,
int
b)
{
static
int
res = a + b;
cout <<
"res => "
<< res <<
", current thread id => "
<< std::this_thread::get_id() << endl;
}
#include <iostream>
#include <thread>
#include <chrono> // std::chrono::seconds
using
namespace
std;
void
func_a();
void
func_b(
int
a,
int
b);
int
main()
{
func_a();
thread
t1(func_b, 1, 2);
thread
t2(func_b, 3, 4);
thread
t3(func_b, 5, 6);
thread
t4(func_b, 7, 8);
std::this_thread::sleep_for(std::chrono::seconds(1));
getchar
();
t1.join();t2.join();t3.join();t4.join();
return
0;
}
void
func_a()
{
static
int
func_a_value = 0x1234;
cout <<
"func_a_value => "
<< func_a_value <<
", current function = > "
<< __FUNCTION__ << endl;
}
void
func_b(
int
a,
int
b)
{
static
int
res = a + b;
cout <<
"res => "
<< res <<
", current thread id => "
<< std::this_thread::get_id() << endl;
}
if
(pOnce > *(
int
*)(NtCurrentTeb()->ThreadLocalStoragePointer[0] + 0x104)
{
_Init_thread_header(&pOnce)
if
( pOnce == -1 )
{
res = b + a;
_Init_thread_footer(&pOnce);
}
}
if
(pOnce > *(
int
*)(NtCurrentTeb()->ThreadLocalStoragePointer[0] + 0x104)
{
_Init_thread_header(&pOnce)
if
( pOnce == -1 )
{
res = b + a;
_Init_thread_footer(&pOnce);
}
}
extern
"C"
void
__cdecl _Init_thread_header(
int
*
const
pOnce) noexcept
{
_Init_thread_lock();
if
(*pOnce == uninitialized)
{
*pOnce = being_initialized;
}
else
{
while
(*pOnce == being_initialized)
{
_Init_thread_wait(xp_timeout);
if
(*pOnce == uninitialized)
{
*pOnce = being_initialized;
_Init_thread_unlock();
return
;
}
}
_Init_thread_epoch = _Init_global_epoch;
}
_Init_thread_unlock();
}
extern
"C"
void
__cdecl _Init_thread_header(
int
*
const
pOnce) noexcept
{
_Init_thread_lock();
if
(*pOnce == uninitialized)
{
*pOnce = being_initialized;
}
else
{
while
(*pOnce == being_initialized)
{
_Init_thread_wait(xp_timeout);
if
(*pOnce == uninitialized)
{
*pOnce = being_initialized;
_Init_thread_unlock();
return
;
}
}
_Init_thread_epoch = _Init_global_epoch;
}
_Init_thread_unlock();
}
extern
"C"
void
__cdecl _Init_thread_footer(
int
*
const
pOnce) noexcept
{
_Init_thread_lock();
++_Init_global_epoch;
*pOnce = _Init_global_epoch;
_Init_thread_epoch = _Init_global_epoch;
_Init_thread_unlock();
_Init_thread_notify();
}
extern
"C"
void
__cdecl _Init_thread_footer(
int
*
const
pOnce) noexcept
{
_Init_thread_lock();
++_Init_global_epoch;
*pOnce = _Init_global_epoch;
_Init_thread_epoch = _Init_global_epoch;
_Init_thread_unlock();
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2023-12-9 22:04
被baolongshou编辑
,原因: