StaticResolver.cpp revision 87f34658dec9097d987d254a990ea7f311bfc95f
15460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao//===- StaticResolver.cpp -------------------------------------------------===// 25460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// 35460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// The MCLinker Project 45460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// 55460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// This file is distributed under the University of Illinois Open Source 65460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// License. See LICENSE.TXT for details. 75460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// 85460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao//===----------------------------------------------------------------------===// 95460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#include <mcld/LD/StaticResolver.h> 105460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#include <mcld/LD/LDSymbol.h> 11affc150dc44fab1911775a49636d0ce85333b634Zonr Chang#include <mcld/Support/MsgHandling.h> 125460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao 135460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaousing namespace mcld; 145460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao 155460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao//========================== 165460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// StaticResolver 175460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei LiaoStaticResolver::~StaticResolver() 185460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao{ 195460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao} 205460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao 21affc150dc44fab1911775a49636d0ce85333b634Zonr Changbool StaticResolver::resolve(ResolveInfo& __restrict__ pOld, 22affc150dc44fab1911775a49636d0ce85333b634Zonr Chang const ResolveInfo& __restrict__ pNew, 2387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines bool &pOverride, LDSymbol::ValueType pValue) const 245460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao{ 255460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao 265460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao /* The state table itself. 275460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao * The first index is a link_row and the second index is a bfd_link_hash_type. 285460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao * 295460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao * Cs -> all rest kind of common (d_C, wd_C) 3087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines * Is -> all kind of indirect 315460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao */ 325460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao static const enum LinkAction link_action[LAST_ORD][LAST_ORD] = 335460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao { 345460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao /* new\old U w_U d_U wd_U D w_D d_D wd_D C w_C, Cs, Is */ 35affc150dc44fab1911775a49636d0ce85333b634Zonr Chang /* U */ {NOACT, UND, UND, UND, NOACT, NOACT, DUND, DUND, NOACT, NOACT, NOACT, REFC }, 36affc150dc44fab1911775a49636d0ce85333b634Zonr Chang /* w_U */ {NOACT, NOACT, NOACT, WEAK, NOACT, NOACT, DUNDW, DUNDW, NOACT, NOACT, NOACT, REFC }, 375460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao /* d_U */ {NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, REFC }, 385460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao /* wd_U */ {NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, REFC }, 395460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao /* D */ {DEF, DEF, DEF, DEF, MDEF, DEF, DEF, DEF, CDEF, CDEF, CDEF, MDEF }, 405460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao /* w_D */ {DEFW, DEFW, DEFW, DEFW, NOACT, NOACT, DEFW, DEFW, NOACT, NOACT, NOACT, NOACT}, 41affc150dc44fab1911775a49636d0ce85333b634Zonr Chang /* d_D */ {MDEFD, MDEFD, DEFD, DEFD, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, MDEF }, 425460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao /* wd_D */ {MDEFWD, MDEFWD, DEFWD, DEFWD, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT}, 435460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao /* C */ {COM, COM, COM, COM, CREF, COM, COM, COM, MBIG, COM, BIG, REFC }, 445460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao /* w_C */ {COM, COM, COM, COM, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, REFC }, 455460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao /* Cs */ {COM, COM, COM, COM, NOACT, NOACT, NOACT, NOACT, MBIG, MBIG, MBIG, REFC }, 465460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao /* Is */ {IND, IND, IND, IND, MDEF, IND, IND, IND, CIND, CIND, CIND, MIND } 475460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao }; 485460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao 495460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao // Special cases: 505460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao // * when a dynamic defined symbol meets a dynamic weak defined symbol, act 515460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao // noting. 525460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao // * when a undefined symbol meets a dynamic defined symbol, override by 535460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao // dynamic defined first, then recover back to undefined symbol later. 545460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao // * when a dynamic defined symbol meets a undefined symbol or a weak 555460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao // undefined symbol, do not override, instead of marking. 565460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao // * When a undefined symbol meets a dynamic defined symbol or a weak 575460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao // undefined symbol meets a dynamic defined symbol, should override. 585460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao // * When a common symbol meets a weak common symbol, adjust the size of 595460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao // common symbol (ref: Google gold linker: resolve.cc) 605460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao 615460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao unsigned int row = getOrdinate(pNew); 625460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao unsigned int col = getOrdinate(pOld); 635460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao 645460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao bool cycle = false; 655460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao pOverride = false; 665460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao ResolveInfo* old = &pOld; 675460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao LinkAction action; 685460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao do { 695460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao cycle = false; 705460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao action = link_action[row][col]; 715460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao 725460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao switch(action) { 735460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao case FAIL: { /* abort. */ 74affc150dc44fab1911775a49636d0ce85333b634Zonr Chang fatal(diag::fail_sym_resolution) 75affc150dc44fab1911775a49636d0ce85333b634Zonr Chang << __FILE__ << __LINE__ 76affc150dc44fab1911775a49636d0ce85333b634Zonr Chang << "mclinker@googlegroups.com"; 77affc150dc44fab1911775a49636d0ce85333b634Zonr Chang return false; 785460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao } 795460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao case NOACT: { /* no action. */ 805460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao pOverride = false; 815460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao old->overrideVisibility(pNew); 825460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao break; 835460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao } 845460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao case UND: /* override by symbol undefined symbol. */ 855460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao case WEAK: /* override by symbol weak undefined. */ 865460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao case DEF: /* override by symbol defined. */ 875460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao case DEFW: /* override by symbol weak defined. */ 885460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao case DEFD: /* override by symbol dynamic defined. */ 895460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao case DEFWD: /* override by symbol dynamic weak defined. */ 905460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao case COM: { /* override by symbol common defined. */ 915460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao pOverride = true; 925460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao old->override(pNew); 935460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao break; 945460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao } 955460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao case MDEFD: /* mark symbol dynamic defined. */ 965460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao case MDEFWD: { /* mark symbol dynamic weak defined. */ 975460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao uint32_t binding = old->binding(); 985460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao old->override(pNew); 995460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao old->setBinding(binding); 100affc150dc44fab1911775a49636d0ce85333b634Zonr Chang ignore(diag::mark_dynamic_defined) << old->name(); 1015460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao pOverride = true; 1025460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao break; 1035460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao } 1045460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao case DUND: 1055460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao case DUNDW: { 1065460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao old->overrideVisibility(pNew); 107affc150dc44fab1911775a49636d0ce85333b634Zonr Chang old->setDynamic(); 1085460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao pOverride = false; 1095460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao break; 1105460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao } 1115460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao case CREF: { /* Possibly warn about common reference to defined symbol. */ 1125460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao // A common symbol does not override a definition. 113affc150dc44fab1911775a49636d0ce85333b634Zonr Chang ignore(diag::comm_refer_to_define) << old->name(); 1145460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao pOverride = false; 1155460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao break; 1165460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao } 1175460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao case CDEF: { /* redefine existing common symbol. */ 1185460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao // We've seen a common symbol and now we see a definition. The 1195460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao // definition overrides. 1205460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao // 1215460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao // NOTE: m_Mesg uses 'name' instead of `name' for being compatible to GNU ld. 122affc150dc44fab1911775a49636d0ce85333b634Zonr Chang ignore(diag::redefine_common) << old->name(); 1235460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao old->override(pNew); 1245460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao pOverride = true; 1255460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao break; 1265460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao } 1275460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao case BIG: { /* override by symbol common using largest size. */ 1285460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao if (old->size() < pNew.size()) 1295460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao old->setSize(pNew.size()); 1305460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao old->overrideAttributes(pNew); 1315460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao old->overrideVisibility(pNew); 1325460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao pOverride = true; 1335460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao break; 1345460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao } 1355460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao case MBIG: { /* mark common symbol by larger size. */ 1365460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao if (old->size() < pNew.size()) 1375460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao old->setSize(pNew.size()); 1385460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao old->overrideVisibility(pNew); 1395460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao pOverride = false; 1405460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao break; 1415460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao } 1425460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao case CIND: { /* mark indirect symbol from existing common symbol. */ 143affc150dc44fab1911775a49636d0ce85333b634Zonr Chang ignore(diag::indirect_refer_to_common) << old->name(); 1445460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao } 1455460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao /* Fall through */ 1465460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao case IND: { /* override by indirect symbol. */ 147affc150dc44fab1911775a49636d0ce85333b634Zonr Chang if (NULL == pNew.link()) { 148affc150dc44fab1911775a49636d0ce85333b634Zonr Chang fatal(diag::indirect_refer_to_inexist) << pNew.name(); 1495460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao break; 1505460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao } 1515460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao 1525460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao /** Should detect the loop of indirect symbol during file reading **/ 1535460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao // if (pNew.link()->isIndirect() && pNew.link()->link() == &pNew) { 1545460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao // m_Mesg = "indirect symbol `"+pNew.name()+"' to `"+pNew.link()->name()+"' is a loop."; 1555460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao // return Resolver::Abort; 1565460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao //} 1575460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao 1585460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao // change the old symbol to the indirect symbol 1595460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao old->setLink(pNew.link()); 1605460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao pOverride = true; 1615460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao break; 1625460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao } 1635460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao case MIND: { /* multiple indirect symbols. */ 1645460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao // it is OK if they both point to the same symbol 1655460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao if (old->link() == pNew.link()) { 1665460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao pOverride = false; 1675460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao break; 1685460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao } 1695460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao } 1705460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao /* Fall through */ 1715460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao case MDEF: { /* multiple definition error. */ 17287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines if (pOld.isDefine() && pNew.isDefine() && 17387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines pOld.isAbsolute() && pNew.isAbsolute() && 17487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines (pOld.desc() == pNew.desc() || pOld.desc() == ResolveInfo::NoType || 17587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines pNew.desc() == ResolveInfo::NoType)) { 17687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines if (pOld.outSymbol()->value() == pValue) { 17787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines pOverride = true; 17887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines old->override(pNew); 17987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines break; 18087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines } else { 18187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines error(diag::multiple_absolute_definitions) << pNew.name() 18287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines << pOld.outSymbol()->value() << pValue; 18387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines break; 18487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines } 18587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines } 186affc150dc44fab1911775a49636d0ce85333b634Zonr Chang error(diag::multiple_definitions) << pNew.name(); 1875460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao break; 1885460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao } 1895460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao case REFC: { /* Mark indirect symbol referenced and then CYCLE. */ 190affc150dc44fab1911775a49636d0ce85333b634Zonr Chang if (NULL == old->link()) { 191affc150dc44fab1911775a49636d0ce85333b634Zonr Chang fatal(diag::indirect_refer_to_inexist) << old->name(); 1925460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao break; 1935460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao } 1945460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao 1955460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao old = old->link(); 1965460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao col = getOrdinate(*old); 1975460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao cycle = true; 1985460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao break; 1995460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao } 200affc150dc44fab1911775a49636d0ce85333b634Zonr Chang default: { 201affc150dc44fab1911775a49636d0ce85333b634Zonr Chang error(diag::undefined_situation) << action << old->name() << pNew.name(); 202affc150dc44fab1911775a49636d0ce85333b634Zonr Chang return false; 203affc150dc44fab1911775a49636d0ce85333b634Zonr Chang } 2045460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao } // end of the big switch (action) 2055460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao } while(cycle); 206affc150dc44fab1911775a49636d0ce85333b634Zonr Chang return true; 2075460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao} 2085460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao 209