Sep 30, 2015

[Note] linking notes

Reference:
Weak_symbol






#if defined _WIN32 || defined __CYGWIN__
  #ifdef BUILDING_DLL
    #ifdef __GNUC__
      #define DLL_PUBLIC __attribute__ ((dllexport))
    #else
      #define DLL_PUBLIC __declspec(dllexport) // Note: actually gcc seems to also supports this syntax.
    #endif
  #else
    #ifdef __GNUC__
      #define DLL_PUBLIC __attribute__ ((dllimport))
    #else
      #define DLL_PUBLIC __declspec(dllimport) // Note: actually gcc seems to also supports this syntax.
    #endif
  #endif
  #define DLL_LOCAL
#else
  #if __GNUC__ >= 4
    #define DLL_PUBLIC __attribute__ ((visibility ("default")))
    #define DLL_LOCAL  __attribute__ ((visibility ("hidden")))
  #else
    #define DLL_PUBLIC
    #define DLL_LOCAL
  #endif
#endif





https://gcc.gnu.org/onlinedocs/gcc-4.9.2/gcc/Visibility-Pragmas.html
#pragma GCC visibility push(visibility)
#pragma GCC visibility pop
This pragma allows the user to set the visibility for multiple declarations without having to give each a visibility attribute.
See Function Attributes, for more information about visibility and the attribute syntax.

In C++, ‘#pragma GCC visibility’ affects only namespace-scope declarations.
Class members and template specializations are not affected; if you want to override the visibility for a particular member or instantiation, you must use an attribute.

extern "C" DLL_PUBLIC void function(int a);
class DLL_PUBLIC SomeClass
{
   int c;
   DLL_LOCAL void privateMethod();  // Only for use within this DSO
public:
   Person(int _c) : c(_c) { }
   static void foo(int a);
};

--------------------------------------------------
__attribute__ ((visibility ("hidden"))) 
只有在 dynamic shared library 才有用。

$ g++ -shared *.o -o fun.so //的時候才有用
$ g++ -c *.cpp // 沒有用 照樣export symbols

*****
用在static library 沒有用!!!!

static library 請用 static or anonymous namespace

------------------------------------------------------

#To generate messages about alignment holes and padding.
$ clang -Wpadded

# list after preprocessing
$ gcc -i <input> -o file.i
$ gcc -E -P -i inputfile -o output.i



# static link:
$ gcc main.cpp -o file.out
$ gcc -static main.cpp -o static.out



-----------
http://ftp.gnu.org/pub/old-gnu/Manuals/ld-2.9.1/html_node/ld_3.html
-E
--export-dynamic
When creating a dynamically linked executable,
add all symbols to the dynamic symbol table.

The dynamic symbol table is the set of symbols which are visible from dynamic objects at run time.

If you do not use this option,
the dynamic symbol table will normally contain only those symbols which are referenced by some dynamic object mentioned in the link.

If you use dlopen to load a dynamic object which needs to refer back to the
symbols defined by the program, rather than some other dynamic object,
then you will probably need to use this option when linking the program itself.
-----------

https://gcc.gnu.org/wiki/Visibility

# whole archive import scenario
# 將不需要的static library symbols include進入 dynamic library

$ gcc -fPIC sour.cpp -Wl, --whole-archive -lstatic_library -o share_library.so

$ gcc -fPIC source.cpp -o a.out
  -Wl, --whole-archive -lstatic_library
  -Wl, --no-whole-archive -lstatic_library


https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html
-rdynamic
Pass the flag -export-dynamic to the ELF linker, on targets that support it. This instructs the linker to add all symbols, not only used ones, to the dynamic symbol table. This option is needed for some uses of dlopen or to allow obtaining back traces from within a program.

$ gcc -fPIC source.cpp -o a.out
  -rdynamic -lstatic_library


#static library:
$ gcc -c a.c b.c

# 或者 with -fPIC , 若此static library要link into dynamic library, -fPIC為必須!

$ gcc -fPIC -c a.c b.c

#compress
$ ar rcs library.a *.o


#dynamic library:
$ gcc -fPIC -c a.c b.c

# 將soname embedded進入 library內 這樣 executable就會以soname在runtime時找此library.

$ gcc -shared a.o b.o -Wl, -soname, libshared.so.1  -o libshared.so.1.1.1

# 注意! 只要有 -lHAHA 最後的executable 便會有DT_NEEDED symbol在內即使executable不需要libHAHA.so的symbols

#soname 將會以 DT_NEEDED的方式顯示在elf內
$ readelf -d a.out


# like Windows, does not allow that symbols is undefined during static linking stage.
# 就像是dynamic library裡有 extern variable, 或是只有function declaration.
$ gcc -fPIC a.c -llibrary -Wl,--no-undefined -o dynamic_library.so

#compile executable:
# 以下這是linker在跑!
# -L 只有對 static linking時有用! runtime時毫無作用!
# Runtime時只會找 dynamic library path 內符合elf需要的DT_NEEDED file :-)
$ gcc main.o -L../tmp -lhaha -o demo.out

# 以下這是compiler在跑, 故傳入-Wl linking command 給linker
$ gcc -Wall -fPIC main.cpp -Wl, -L../tmp, -Wl, -lhaha -o demo.out


# ** 可以傳入完整的library 檔名給 -l , 加上 : 即可!
$ gcc main.cpp -l:libhaha.so.1


# convert .so into exectable
1. implement main() function inside the .so library
int main()
{
  _exit(0); // no return function!
}

2.
$ gcc -shared -Wl, -e, main -o libhaha.so

3.
specify interpreter to be the dynamic linker:

const char service_interp[] __attribute__((section(".interp"))) =
  "/lib/ld-linux.so.2";


4.
build the library without optimization! no -O3 etc.



#**Preload library:
set env variable:
$ export LD_PRELOAD=/tmp/a.so:/tmp/b.so
or
$ /etc/ld.so.preload

LD_LIBRARY_PATH // Run time set library path
LD_RUN_PATH // Linking time set library path


#rpath:
如果
rpath沒有被設定,
$ export LD_LIBRARY_PATH=/tmp:$LD_LIBRARY_PATH
才會被看見!!!
也就是 rpath > LD_LIBRARY_PATH

注意!
LIBRARY_PATH
是給static linking時用的!!

$ gcc -Wl, -R/tmp -lhaha
$ gcc -Wl, -R./tmp -lhaha


$ export LD_RUN_PATH=/tmp:$LD_RUN_PATH


#runpath: elf 內的 DT_RUNPATH
# 若設定runpath, 則LD_LIBRARY_PATH 有最高權限 LD_LIBRARY_PATH > runpath
# 若設定runpath, DT_RPATH將被設定與runpath相同, 但, loader因為看到
  runpath, 而會忽略 rpath, 因此 , LD_LIBRARY_PATH可以被看見!

$ gcc -Wl, -R/tmp -Wl, --enable-new-dtags -lhaha

**priority:
runpath被設定:
1. LD_LIBRARY_PATH
2. runpath
3. ld.so.cache
4. default library path /lib , /usr/lib etc.

runpath沒有被設定:
1. RPATH
2. LD_LIBRARY_PATH
3. ld.so.cache
4. default library path




--
#patchelf 用來修改 rpath/runpath information!
$ patchelf --set-rpath /tmp:/tmp/tmp a.out











--
/etc/ld.so.conf //設定哪裡(path)load dynamic library
/etc/ld.so.cache


**default library path:
/lib
/lib64
/usr/lib
/usr/lib64


/usr/local/lib 不在預設裡面!!!




#symbol export
1. use strip over the dynamic library.
$ strip --strip-symbol symbolsXXX library.so


2.
https://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/Code-Gen-Options.html
https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/CppRuntimeEnv/Articles/SymbolVisibility.html
# -fvisibility=hidden makes all your symbols hidden by default.
# -fvisibility=internal flag goes much further than the hidden flag.
  It tells the compiler that ABI compatibility isn't important,
  since nobody outside the module will ever use the function.
  If some outside code does manage to call the function, it will probably crash.
  same as:
  __attribute__((visibility("internal"))) void MyFunction1() {}

$ gcc -fvisibility=hidden -shared a.o -o library.so

3.
__attribute__((visibility("hidden"))) void MyFunction1() {}


4.
#pragma GCC visibility push(hidden)
void MyFunction1() {}
#pragma GCC visibility pop

5.
$ gcc -shared a.o b.o -Wl, --version-script, script.ss -o libhaha.so

script.ss:

LIBSIMPLE_1.0 {
  global:
    function_a; functionb;
  local:
    *;
};


**
#weak symbols:
int __attribute__((weak)) function_ha();










# convert static library to dynamic library:
$ ar -x statiblibrary.a
# 以上的.o 務必是compiled with -fPIC!!!
$ gcc -shared *.o -o shared.so



















# assembly
$ gcc -S -masm=intel inputfile -o out.s


---
objdump:
#dump object symbol
$ objdump -D -M intel file.o

#dump object's section info
$ objdump -x -j .bss file.o

# 對於不信任的 binary, 不要用ldd!! 用objdump -p
$ objdump -p a.so |grep NEEDED
$ readelf -d a.so |grep NEEDED


# 產出assembly code!
$ objdump -d -Mintel a.so
$ objdump -d -S -Mintel a.so //assembly 與 src code 對照!





---
readelf:
# read segment from binary
$ readelf --segments file.so

#read symbols: 可以找 DT_NEEDED 即此excutable 所需的dynamic library name
$ readelf -d aa.so


---
ldconfig:
# 將directory內所有 XXX.so.m.n.p 建立一個 soft link with it's soname! => libhaha.so.1
$ ldconfig -n directory

# 即使 so_file_name 不是 xxx.so.m.n.p 格式也無所謂 會將其 embedded 的 soname抓出來.
$ ldconfig -l so_file_name


---
file: give file information
$ file a.so


--
size: give each section's lengh info
$ size a.so

--
ldd: link info. 可能會執行binrary file! 所以不信任的code不要用ldd!
      改用objdump -p 或者是 readelf -d
$ ldd a.so


--
nm: list symbols of binary files
$ nm a.so
$ nm -D a.so // only list symbols in the dynamic section / exported visible symbols
$ nm -C a.so // with demangled format
$ nm -D --no-demangle a.so //對於檢查library忘了使用extern "C" 很有幫助!!
$ nm -A lib_directory
$ nm -u a.so //檢測 undefined symbols









-------
object file:
1. symbol
2. section <=> segment(final program)
--
.text
.data
.bss
.debug info


**Each section of the object file's memory address range is set
from 0.

The actual section's memory address will be set during the linking stage.

The length of each section of the point.(i.e range of the section)

**
There's no section contributed to stack or heap.
stack and heap are determined in runtime.

For final program, sections compose to segment.











-------
Simple!
To know the _address_ of variable/function.

對於在其他TU內的function/variable , 在linking stage這是個棘手的問題

然, 對於TU內reference到同一個TU內的global variable/function,

這不是問題. 直接提供 memory offset即可(連linking stage 都不需經手!)
注意喔! 這裡指的是 non-externed variable/function 才可以直接用offset.
若dynamic library內的variable/function是extern symbol, 仍是透過GOT/PLT
這樣, 才能夠控制, dynamic library內reference到這些variable/function是
此library內的還是其他library的!

-------

靜態Linker stage:
1. examine the sections already tiled together in the program memory map
2. find out which part of the code makes calls outside of its orginal section
(即 call 出此TU以外)

3. figure out where exactly (at which address in the memory map)
  the referenced part of the code resides.
4. resolve the references by replacing "dummy addresses" aka. "placeholder"
    in the machine instructions with the actual adresses of the program memory map.

-------
.text section not only contains the individual tiles from object files,
but the linker modified it to make sure that all the references,
between the individual tiles have been resolved.

-------
crt0:
  first part of program code gets exec under the control of kernel
crt1:
  more modern startup routune with support for tasks to be completed
  before the main function gets exec and **after the program terminates.**
-------


Kernal virtual memory:
-----
Process-specific data structure
--
physical memory
--
kernel code and data

env variable
argv argc
-----
**以上fork 時會被copy
**以下v-memory 會被0 out during calling exec......
也就是為什麼 exec後 pid相同。

Process virtual memory:
-----
user stack
  <-- %esp
--
Memory mapped region for shared libraries (在實際physical memory上是不變得!)
--
  <--brk
--
run-time heap
--
.bss
--
.data
--
.text
--
crt1
--
 <-- 0
------



-----------------------
exec:
只有 env variable會被copy.
其他的0 out.

1.
也就是, kernel virtual memory會由kernel複製/更改,
process virtual memory 0-out(由loader填入相關address info)

2.
然後呼叫 exec family(system call to sys_execve)

3.
檢查 被呼叫檔案的格式

4.
 kernel loader開始跑, 首先檢查:
 PT_INTERP segment , 這個用來輔助dynamic loading library





--------------
Loader:
1. 將 executable 內的 section load 入 memory 內

2. 只注意 binary file 內的 section 為
  read-only
  read-write
  need patch before run? (GOT)

3. after loading, loader takes a quick look at the value of e_entry field from ELF

4. e_entry value carries nothing less than the first address of the code(.text)
  section.
  Coincidentally, this program memory address typically denotes the origin of
  the _start function.

5. _start() function:
  prepare the input arguments for the __libc_start_main function that will be called next.

int __libc_start_main(
  int (*main)(int, char **, char**),
  int argc,
  char ** ubp_av,
  void(*init)(void),
  void(*fini)(void),
  void(*rtld_fini)(void), // dynamic linker fini function
  void(*stack_end)); // end of stack address

6. __libc_start_main:
  1. starts up program threading
  2. call _init()
    __attribute__((constructor))
  3. **registers** the _fini() and _rtld_fini(). called after program terminiates.
    __attribute__((destructor))
  4. call main()



To have a function executed whenever the shared library is loaded or unloaded, we can mark a constructor and destructor function using GCC-specific attribute syntax:
__attribute__((constructor)) void init(void) { ... } 
__attribute__((destructor)) void fini(void) { ... }

Because various parts of a C environment depend on things being initialized in the standard .init code added by GCC behind the scenes, directly using
-Wl,-init,<function name>
may cause your program to crash.

For more information, see the Libary HOWTO on Library constructor and destructor functions.

reference:
[stackoverflow] Automatically executed functions when loading shared libraries
How exactly does __attribute__((constructor)) work?
--------------
**
the stack memory is not unlimited.
The amount of available stack memory is bound with the
amount of memory available for allocation(heap)







--------------
function calling convention:
cdecl (!! default !!)
stdcall
fastcall
thiscall



--------------
dynamic library:

linux allows some the symbols be unresolved with the expectation that they will
eventually show up in the final binary after other dynamic library is linked in.
以-c 來說,可以有symbol undefined.
但在最後產生exec program時,這些必須被產生。


***
Linker, for dynamic library, only check the symbols that it is resides inside this dynamic library. That's it!
Linker doesn't care about .text or .data, only symbols!
只是要確定有variable/function symbols(包含ABI! 不然怎麼prelocate argument size in stack?).
然後把此.so 放入DT_NEEDED 給loader runtime時patch.


during runtime:
1. the dynamic binary has been found.
2. dynamic binary should load into memory succefully.

3. **the dynamic binary will be loaded iff the symbols inside
  exactly match to the symbols during link time.

4. ** the symbol doesn't need to be the one resides in the same section
  during the linking time!

5.the executable symbols need to be resolved to point to the right
  address in the part of process of memory map where the dynamic library is mapped
  into. This is dynamic linking.

dynamic library can be compiled linking to other static/dynamic libraries.

--------------------












---------------------
******
ABI:
ABI as a set of symbols(primarily a set of function entry points)
created in the process of compiling/linking of the source code interface.

1. During the first(build-time) phase of the dynamic linking, the client binary in this face links against the library's exported ABI!

i.e remember? during this phase, we only check the library's symbols.
which is that, checks whether the dynamic library exports
the symbols(function pointers such as the ABI) and !does not! care at all about the sections(the function bodies).

2. Second phase, the dynamic library must export the unchanged ABI,
same to that found at build time.
---------------------










---------------------
static library:
只 copy 需要的 .o files into executable!

dynamic library:
load 整個.so into memory!












---------------------
Whole archive import scenario:

Intermediary dynamic library:
  本身不需要這些static library的symbols.
  只做為中介 因此把 static library 的 symbols include進來.








---------------------
static library:
strict ODR
由  至  load!!!


dynamic library:
先load 先贏!!


--------------------
**務必用dynamic library實做 singleton!!













--------------------
Static libraries issue on 64bit linux:
若要將static library link into dynamic library, 務必:

1. *.o 是 compiled with -fPIC
2. 或者是 compiled with -mcmodel=large












--------------------
-fPIC 不是決定此.o是否為dynamic library與否

-shared 才是!!












-----------------------
即是純 c style function, 在c++ 下 linker還是有可能會name mangling it!!

According to §7.5¶7 in the standard :

A declaration directly contained in a linkage-specification is

treated as if it contains the extern specifier (§7.1.1) for the purpose

of determining the linkage of the declared name and whether it is a definition.

--
extern "C" int x; //is just a declaration
extern "C" { int y; } //is a definition
--













--------------------
ODR:
http://vsdmars.blogspot.com/2012/03/c-one-definition-rule-excerpt-from-c.html
One-per-Program Constraints

ODR-use:
Informally, an object is odr-used if its value is read (unless it is a compile time constant) or written, its address is taken, or a reference is bound to it; a reference is odr-used if it is used and its referent is not known at compile time; and a function is odr-used if a function call to it is made or its address is taken. If an object, a reference or a function is odr-used, its definition must exist somewhere in the program; a violation of that is usually a link-time error.


There can be at most one definition of the following items per program:
1. Noninline functions and noninline member functions

2. Variables with external linkage
  (essentially, variables declared in a namespace scope
  or in the global scope, and with the static specifier (i.e, static class data member) )

3. Static data members

4. Noninline function templates,
  noninline member function templates,
  and noninline members of class templates when they are declared with export

5. Static data members of class templates when they are declared with export:

  For example,
  a C++ program consisting of the following two translation units is invalid :
    Interestingly, it is valid C because C has a concept
    of  tentative definition, which is a variable definition
    without an initializer and can appear more than once in a program.
 
// Translation unit ONE:
int counter;
// Translation unit  TWO:
int counter; // ERROR: defined twice! (ODR violation)

//===================================================================================

A class type X (including structs and unions) must be defined in a
translation unit prior to any of the following kinds of uses in that translation unit:

1. The creation of an object of type X
(for example, as a variable declaration or through a new expression).

2. The creation could be indirect, for example,
  when an object that itself contains an object of type X is being created.

3. The declaration of a data member of type X.

4. Applying the sizeof or typeid operator to an object of type X.

5. Explicitly or implicitly accessing members of type X.

6. Converting an expression to or from type X using any kind of conversion,
  or converting an expression to or from a pointer or reference to X
  (except void*) using an implicit cast, static_cast, or dynamic_cast.

7. Assigning a value to an object of type X.

8. Defining or calling a function with an argument or return type of type X.
   Just declaring such a function doesn't need the type to be defined however.
   但仍須forward declare 此 symbol。




------------------------
non-local static objects:
whose visibility scope exceeds the boundary of a class.
1. defined at global or namespace scope
2. declared static in a class
3. defined static at file scope // anonymous namespace variable

這些會在program開始時被初始化!
這些static object會以出現在TU內的順序初始化
但是!!
**在整個program中初始化的順序不定!!!!!!!!!












--------------------
ABI Design:
1. implement ABI as a set of c-style functions

2. provide the header file carrying the complete ABI declaration.
  i.e function declaration.

3. use widely-supported standard C keywords

4. Use a class factory mechanism(C++) or module (C)

5. export only the only important Symbols!!
  in linux, all symbols are exported by default.

6. Use namespace to avoid symbol naming collision.













-----------------
During linking stage, those link with dynamic library symbols,
will mark as:
"U" for undefined
while compiling.

Could make as strict as the same as Windows:
--no-undefined
















--------------------
dynamic linking:

分兩種:

第一種:
executable runtime linking loader:
1. static link時 dynamic library的 ABI 要export, 與 header interface內 declaration相同.

2. dynamic linking:
  1. the list of dynamic libraries required by the project

  2. path to the dynamic library binaries needed by the client binary in order
    to setup the list of expected library symbols. 就是 rpath etc.
 
  3. optional linker flags specifying the details of the linking process


第二種:
用 dlopen etc.
1.
dlopen
dlsym
dlclose
dlerror

2. executable 還是一樣要include header , which expose ABI declaration!





















---------------------
naming convention:

static library:

libHAHA.a


dynamic library:
libHAHA.so.M.m.p

soname:
給 executable 跑時 dynamic loading 用的!
libHAHA.so.M

.so:
給static linking 用的!
$ gcc -lhaha // 使用libhaha.so














---------------------
Library location guideline:

1. folder path / library filename
2. folder path => -L
3. library filename => -l

$ gcc main.o -L../tmp -lhaha -o demo.out

***千萬不要把完整路徑 path + filename 傳入 linker through -l 在compile的時候!!
這樣在 running exectable 時, 也會以此完整路徑找dynamic library!

-L 只有對 static linking時有用! 即compile時用的!! runtime時毫無作用!


























-----------------------
Preload library:

set env variable:
LD_PRELOAD=/tmp/a.so:/tmp/b.so
or
/etc/ld.so.preload

















----------------------
rpath:
runpath / aka DT_RUNPATH in elf <= higher priority

rpath  /
  aka DT_RPATH in elf <= 如果上面沒有, 則此為最高priority. 若DT_RUNPATH有東西, 則此被忽略!














------------------
Which symbols are likely to suffer from address translation?

Only the functions and variables whose symbols are *exported* by dynamic library
are guaranteed to suffer from the negative effects of the address translation.













--------------------

--
dynamic library address range inside a process v-memory layout
--

--
GOT
0
1
2
3
....
--
PLT //也在data 不過是read only的
0
1
2
3
....
--


--
.data
int a;
(this is from dynamic library global variable
during static linking stage, 存的是placeholder 0,
當runtime load時, 將會把dynamic library裡的值複製過來.
GOT[1] 到 .data int a的offset compile time已知.
GOT[1] 存的是 int a的address.
由此, 即使是 dynamic library裡的function要存取 int a,
都可經由 GOT[1] 存取.)

--
.text
function ha()
( 將會呼叫 PLT[2]
第一次呼叫時 PLT[2]會叫 GOT[2]
GOT[2]回叫 PLT[2]的prepare resolver (準備resolver的argument) 然後 JMP to PLT[0] (resolver本身)
PLT[0] 內有 resolver
resolver 會算出dynamic library內此function 在此process 的v-memory layout在那.
將 v-memory的位址存回 GOT[2].
下次呼叫 PLT[2] 直接叫 GOT[2] 直接跳到 此function ha() 的絕對位置.






-----------------
static library or .o files:

ODR 絕對限制!

static variable/function 可以允許 因為只在此 TU 內.



dynamic library:
不嚴格執行 ODR
先load 先贏!!



--
*******
symbol resolve priority: 是在static linking time!!!
這裡只的找是指linking time找symbol 不是resove symbol!!

Location, Location, Location:

Code Priority Zoning Rules


  The variety of linker symbols participating in building the client binary may reside in a variety of locations.
  The first criterion that the linker applies toward resolving name collisions between symbols is based on the comparison between the following symbols priority scheme.

First Level Priority Symbols:

Client Binary Symbols
The initial ingredient of building the binary file is the collection of its object files, which are either indigenous to the project or come in the form of the static library.
In the case of Linux, the sections coming from these ingredients typically occupy the "lower part" of the process memory map.

Second Level Priority Symbols:

Dynamic Library Visible Symbols
The dynamic library exported symbols (residing in the dynamic section of the dynamic libraries) are taken by the linker as the next priority level in the priority scheme.

Third Level Priority:

(Unprioritized, Noncompeting) Symbols
The symbols declared as static are typically never the subject of the duplicated symbol name conflicts,
regardless of whether they belong to the client binary or to the statically aware linked dynamic library.
To the same group belong the dynamic library’s stripped off symbols, which obviously do not participate in the stage of linking the client binary.

***
注意!
當symbol name相同存在於 static library, dynamic library時,
不管load 順序! static library 的symbols ALWAYS WIN!!! 因為是最優先找!!
static library symbols 屬於 1st level!!
**

singleton 千萬不能以 static library實做!
因為static library symbols會被複製一份至個各 TU!
就不是 singleton 啦!!

要以dynamic library實做! symbol 先 load 先贏!! 只有一個!

兩種方式:
1. 將singleton static library link入dynamic library, 由
dynamic library export他! 因為dynamic library 先load先贏。

2. 直接將singleton function實做入 dynamic library.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.