{"id":21098777,"url":"https://github.com/tinyadapter/tinylinker","last_synced_at":"2025-10-24T04:26:50.058Z","repository":{"id":83077027,"uuid":"162952604","full_name":"tinyAdapter/tinylinker","owner":"tinyAdapter","description":"NYU's Design of Operating Systems - Lab 1 (SCU modified version)","archived":false,"fork":false,"pushed_at":"2018-12-26T16:23:02.000Z","size":624,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-09-15T06:50:57.576Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tinyAdapter.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2018-12-24T05:16:38.000Z","updated_at":"2024-12-04T12:45:04.000Z","dependencies_parsed_at":null,"dependency_job_id":"be9e771c-28e6-45a9-b845-57227cef6d40","html_url":"https://github.com/tinyAdapter/tinylinker","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/tinyAdapter/tinylinker","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinyAdapter%2Ftinylinker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinyAdapter%2Ftinylinker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinyAdapter%2Ftinylinker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinyAdapter%2Ftinylinker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tinyAdapter","download_url":"https://codeload.github.com/tinyAdapter/tinylinker/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinyAdapter%2Ftinylinker/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":280736998,"owners_count":26382365,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-24T02:00:06.418Z","response_time":73,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-19T22:56:37.624Z","updated_at":"2025-10-24T04:26:50.053Z","avatar_url":"https://github.com/tinyAdapter.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# TinyLinker\n\n本项目为 NYU 《操作系统设计》课程的实现代码。\n\n项目要求见`instructions/NYU_lab instruction.pdf`。\n\n(`instructions/SCU_TinyLinker instruction.doc`中有部分中文说明)\n\n说明：在本版 TinyLinker 中，由于需要用到字符串，变长数组和字典等数据结构，而自行实现容易出现 BUG，因此直接套用 C++ STL 库中的 `std::string`, `std::vector`, `std::map` 类。该变化对 VC++ 6.0 下的编译过程无任何影响。\n\n## 数据结构\n\n为组织方便，TinyLinker 中设计了一些数据结构，如下表所示。\n\n| 结构名     | 说明                                                         |\n| ---------- | ------------------------------------------------------------ |\n| ListItem   | 单个 Definition / Use 中（S, R）键值对的抽象                 |\n| TextItem   | 单个 Program Text 中（type, word）对的抽象                   |\n| ObjectFile | 单个文件的抽象，包含 Definition List, Use List, Program Text |\n| SymbolItem | Symbol Table 中单个 Symbol 的抽象，并记录错误信息            |\n| MapItem    | Memory Map 中单个 Word 的抽象，并记录错误信息                |\n\n## 函数过程\n\n整个运行过程如下：\n\n1. `processOne()` 是 Linker 的第一次遍历，用于将全部文件信息存储到文件列表 g_objectFiles 中，形成拓扑，并在存储过程中构造 Symbol Table；\n2. `processTwo()` 是 Linker 的第二次遍历，用于解释各个 Program Text，根据 Symbol Table 计算绝对地址并重定位符号位置，最终通过调用 `printToOutputFile()` 将结果一次性打印到 output 文件中。\n\n## 附加需求实现\n\n在项目需求文档中，提出了一系列附加需求。针对这些需求，TinyLinker 给出了解决方案：\n\n### Arbitrary spaces / lines between items.\n\n通过 `fscanf` 指定数据类型，跳过空格和空行，从而正常读取文件。\n\n### If a symbol is multiply-defined, print an error message and use the value given in the first definition.\n\n在第一次遍历构造 Symbol Table 时，插入新 Symbol 前检查该变量是否已经在表中，如果存在，记录错误信息（将 `SymbolItem::isDuplicated` 置为 `true`）。\n\n```cpp\n// fill in symbol table\nif (g_symbolTable.find(variableName) == g_symbolTable.end()) {\n// do not find duplication\n\tg_symbolTable.insert(\n\t\tstd::pair\u003cstd::string, SymbolItem\u003e(\n\t\t\tvariableName, SymbolItem(g_offset + innerOffset, fileIndex)));\n}\nelse {\n\tg_symbolTable[variableName].isDuplicated = true;\n}\n```\n\n### If a symbol is used but not defined, print an error message and use the value zero.\n\n在第二次遍历通过 Use List 重定位时，尝试检查变量在 Symbol Table 中是否存在，若不存在，记录错误信息（将 `MapItem::isNotDefined` 置为 `true`）后将 `word` 重置为 1000。\n\n```cpp\n// handle errors\nstd::map\u003cstd::string, SymbolItem\u003e::iterator tryFindSymbol = g_symbolTable.find(useList[k].variableName);\nif (tryFindSymbol == g_symbolTable.end()) {\n\tg_memoryMap[g_offset + currentRefIndex].isNotDefined = true;\n\tg_memoryMap[g_offset + currentRefIndex].word = 1000;\n\tg_memoryMap[g_offset + currentRefIndex].variableName = useList[k].variableName;\n\tcontinue;\n}\nelse {\n\t// now the symbol is used\n\ttryFindSymbol-\u003esecond.isUsed = true;\n}\n```\n\n### If a symbol is defined but not used, print a warning message and continue.\n\n参见上方代码，如果变量被使用，则将其 `SymbolItem::isUsed` 置为 `true`。在打印结果时，如果发现某一变量的 `isUsed` 没有被置为 `true`，则输出警告信息。\n\n```cpp\nfor (std::map\u003cstd::string, SymbolItem\u003e::iterator it = g_symbolTable.begin();\n\tit != g_symbolTable.end();\n\tit++) {\n\tif (!it-\u003esecond.isUsed) {\n\t\tfprintf(out, \"Warning: %s was defined in module %d but never used.\\n\",\n\t\t\tit-\u003efirst.c_str(), it-\u003esecond.definedModule);\n\t}\n}\n```\n\n### If an address appearing in a definition exceeds the size of the module, print an error message and treat the address given as 0 (relative).\n\n在第一次遍历结束时，读取全部 Definition List 中变量并检查是否超出 Program Text 长度，如果出现该类型变量，记录错误信息（将 `SymbolItem::isOutsideModule` 置为 `true`）后将其 `SymbolItem::globalOffset` 置为 `g_offset`（相对地址 0）。\n\n```cpp\n// check if definition of variables are outside the module\nfor (int k = 0; k \u003c g_objectFiles.back().definitionList.size(); k++) {\n\tstd::string variableName = g_objectFiles.back().definitionList[k].variableName;\n\tif (g_objectFiles.back().definitionList[k].offset\n\t\t\t\u003e= g_objectFiles.back().programText.size()\n\t\t\t\u0026\u0026 g_symbolTable[variableName].isDuplicated == false) {\n\t\tg_symbolTable[variableName].isOutsideModule = true;\n\t\t// reset address to zero (relative)\n\t\tg_symbolTable[variableName].globalOffset = g_offset;\n\t}\n}\n```\n\n### If an address appearing in a use list exceeds the size of the module, print an error message and treat the address as the sentinel ending the list.\n\n在第二次遍历根据 word 信息跳转到下一个使用变量的地址前，检查其是否超出 Program Text 长度，如果出现该类型变量，记录错误信息（将 `MapItem::isOutsideModule` 置为 `true`）后直接结束该变量的重定位过程。\n\n```cpp\nif (programText[currentRefIndex].word % 1000 \u003e= programText.size()\n\t\t\u0026\u0026 programText[currentRefIndex].word % 1000 != 777) {\n\t// reference address is outside the module\n\tg_memoryMap[g_offset + currentRefIndex].isOutsideModule = true;\n\tbreak;\n}\n```\n\n### If an address on a use list is not type E, print an error message and treat the address as type E.\n\n针对每个被重定位的变量，将其 `MapItem::isOnChain` 置为 `true`。\n在打印结果时检查，如果变量的 `originalType` 不为 E，但其 `isOnChain` 为 `true`，说明其在 Use List 中，打印错误信息。\n\n```cpp\nelse if (g_memoryMap[i].originalType != 'E' \u0026\u0026 g_memoryMap[i].isOnChain == true) {\n\tfprintf(out, \" Error: %c type address on use chain; treated as E type.\\n\", g_memoryMap[i].originalType);\n}\n```\n\n### If a type E address is not on a use list, print an error message and treat the address as type I.\n\n同上，在打印结果时检查，如果变量的 `originalType` 为 `E`，但其 `isOnChain` 为 `false`，说明其不在 Use List 中，打印错误信息。\n\n```cpp\nelse if (g_memoryMap[i].originalType == 'E' \u0026\u0026 g_memoryMap[i].isOnChain == false) {\n\tfprintf(out, \" Error: E type address not on use chain; treated as I type.\\n\");\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftinyadapter%2Ftinylinker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftinyadapter%2Ftinylinker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftinyadapter%2Ftinylinker/lists"}