Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix extern #5

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 31 additions & 5 deletions elf_binary.cc
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,14 @@ bool ELFBinary::IsAddrInInitarray(uintptr_t addr) const {
}

bool ELFBinary::IsAddrInFiniarray(uintptr_t addr) const {
CHECK(fini_array_addr_ != 0);
LOG(INFO) << SOLD_LOG_BITS(addr) << SOLD_LOG_BITS(fini_array_addr_) << SOLD_LOG_BITS(fini_arraysz_);
return reinterpret_cast<uintptr_t>(fini_array_addr_) <= addr && addr < reinterpret_cast<uintptr_t>(fini_array_addr_ + fini_arraysz_);
if (fini_array_addr_ != 0) {
LOG(INFO) << SOLD_LOG_BITS(addr) << SOLD_LOG_BITS(fini_array_addr_) << SOLD_LOG_BITS(fini_arraysz_);
return reinterpret_cast<uintptr_t>(fini_array_addr_) <= addr &&
addr < reinterpret_cast<uintptr_t>(fini_array_addr_ + fini_arraysz_);
} else {
LOG(WARNING) << SOLD_LOG_KEY(fini_array_addr_);
return false;
}
}

bool ELFBinary::IsVaddrInTLSData(uintptr_t vaddr) const {
Expand Down Expand Up @@ -194,9 +199,16 @@ void ELFBinary::ReadDynSymtab(const std::map<std::string, std::string>& filename
syms_.push_back(Syminfo{symname, soname, version, v, sym});
CHECK(duplicate_check.insert({symname, soname, version}).second)
<< SOLD_LOG_KEY(symname) << SOLD_LOG_KEY(soname) << SOLD_LOG_KEY(version);
const void* symp = nullptr;
if (IsAddrInBinary(sym->st_value)) {
symp = reinterpret_cast<const void*>(head() + OffsetFromAddr(sym->st_value));
}
LOG(INFO) << SOLD_LOG_BITS(symp) << SOLD_LOG_BITS(sym->st_size);
symps_.emplace_back(symp);
LOG(INFO) << "duplicate_check: " << SOLD_LOG_KEY(symname) << SOLD_LOG_KEY(version);
}

CHECK_EQ(syms_.size(), symps_.size());
LOG(INFO) << "nsyms_ = " << nsyms_;
}

Expand Down Expand Up @@ -265,7 +277,8 @@ std::pair<std::string, std::string> ELFBinary::GetVersion(int index, const std::
if (vd->vd_flags & VER_FLG_BASE) {
soname = std::string(strtab_ + vda->vda_name);
}
if (vd->vd_ndx == versym_[index]) {
LOG(INFO) << SOLD_LOG_BITS(vd->vd_ndx);
if (vd->vd_ndx == (VERSYM_VERSION & versym_[index])) {
version = std::string(strtab_ + vda->vda_name);
}

Expand All @@ -277,7 +290,7 @@ std::pair<std::string, std::string> ELFBinary::GetVersion(int index, const std::
}
}

LOG(WARNING) << "Find no entry corresponds to " << versym_[index];
LOG(WARNING) << "Find no entry corresponds to " << SOLD_LOG_BITS(versym_[index]);
return std::make_pair("", "");
}
}
Expand Down Expand Up @@ -592,6 +605,19 @@ void ELFBinary::ParseFuncArray(uintptr_t* array, uintptr_t size, std::vector<uin
}
}

// TODO(akawashiro): Merge with OffsetFromAddr
bool ELFBinary::IsAddrInBinary(const Elf_Addr addr) const {
for (Elf_Phdr* phdr : loads_) {
if (phdr->p_vaddr <= addr && addr < phdr->p_vaddr + phdr->p_memsz) {
return true;
}
}
if (tls() != nullptr && tls()->p_vaddr == addr) {
return true;
}
return false;
}

Elf_Addr ELFBinary::OffsetFromAddr(const Elf_Addr addr) const {
for (Elf_Phdr* phdr : loads_) {
if (phdr->p_vaddr <= addr && addr < phdr->p_vaddr + phdr->p_memsz) {
Expand Down
6 changes: 5 additions & 1 deletion elf_binary.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ class ELFBinary {
const std::vector<uintptr_t>& fini_array() const { return fini_array_; }

const std::vector<Syminfo>& GetSymbolMap() const { return syms_; }
const std::vector<const void*> symps() const { return symps_; }

Range GetRange() const;

Expand Down Expand Up @@ -108,6 +109,7 @@ class ELFBinary {

std::pair<std::string, std::string> GetVersion(int index, const std::map<std::string, std::string>& filename_to_soname);

bool IsAddrInBinary(const Elf_Addr addr) const;
Elf_Addr OffsetFromAddr(const Elf_Addr addr) const;
Elf_Addr AddrFromOffset(const Elf_Addr offset) const;

Expand Down Expand Up @@ -160,9 +162,11 @@ class ELFBinary {
std::vector<uintptr_t> init_array_;
std::vector<uintptr_t> fini_array_;

// This is the name on the filsysytem
// This is the name on the filesystem
std::string name_;
std::vector<Syminfo> syms_;
// Addresses of locations which symbols refer to
std::vector<const void*> symps_;

int nsyms_{0};

Expand Down
1 change: 1 addition & 0 deletions feature_unit_tests/extern/hoge.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ int hoge_var = 0xdeadbeef;

void inc() {
hoge_var++;
printf("%s:%d hoge_var = %x &hoge_var = %x\n", __FILE__, __LINE__, hoge_var, &hoge_var);
}
9 changes: 4 additions & 5 deletions feature_unit_tests/extern/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@ int fuga_var = 0xaaaaaaaa;
void inc();

int main() {
printf("hoge_var = %x &hoge_var = %x\n", hoge_var, &hoge_var);
printf("hoge_var = %x &hoge_var = %x\n", *((&hoge_var - 1)), (&hoge_var - 1));
printf("hoge_var = %x &hoge_var = %x\n", *((&hoge_var - 2)), (&hoge_var - 2));
printf("%s:%d hoge_var = %x &hoge_var = %x\n", __FILE__, __LINE__, hoge_var, &hoge_var);
printf("%s:%d *((&hoge_var - 1)) = %x &(&hoge_var - 1) = %x\n", __FILE__, __LINE__, *((&hoge_var - 1)), (&hoge_var - 1));
printf("%s:%d *((&hoge_var - 2)) = %x &(&hoge_var - 2) = %x\n", __FILE__, __LINE__, *((&hoge_var - 2)), (&hoge_var - 2));
assert(hoge_var == 0xdeadbeef);
inc();
printf("hoge_var = %x &hoge_var = %x\n", hoge_var, &hoge_var);
printf("%s:%d hoge_var = %x &hoge_var = %x\n", __FILE__, __LINE__, hoge_var, &hoge_var);
assert(hoge_var == 0xdeadbeef + 1);
hoge_var = 3;
return 0;
}
3 changes: 0 additions & 3 deletions feature_unit_tests/extern/test.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
#! /bin/bash -eux

pushd ~/sold/build
ninja
popd
gcc hoge.c -fPIC -shared -Wl,-soname,libhoge.so -o libhoge.so
gcc main.c libhoge.so -rdynamic -export-dynamic
# GLOG_logtostderr=1 ../../build/print_dynsymtab libhoge.so
Expand Down
3 changes: 1 addition & 2 deletions feature_unit_tests/run-all-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
unexpected_failed_tests=
unexpected_succeeded_tests=

# TODO(akawashiro): extern
for dir in hello-g++ hello-gcc just-return-g++ just-return-gcc simple-lib-g++ simple-lib-gcc version-gcc tls-lib-gcc tls-lib-gcc-without-base tls-multiple-lib-gcc tls-thread-g++ call_once-g++ inheritance-g++ typeid-g++ dynamic_cast-g++ tls-dlopen-gcc static-in-function-g++ static-in-class-g++ tls-multiple-module-g++ exception-g++ stb_gnu_unique_tls setjmp-gcc tls-bss-gcc tls-bss-g++ hello-g++-aarch64 hello-gcc-aarch64 just-return-g++-aarch64 simple-lib-g++-aarch64 simple-lib-gcc-aarch64 version-gcc-aarch64 tls-bss-gcc-aarch64 tls-bss-g++-aarch64 just-return-gcc-aarch64 setjmp-gcc-aarch64 exception-g++-aarch64 typeid-g++-aarch64 inheritance-g++-aarch64 dynamic_cast-g++-aarch64 static-in-class-g++-aarch64 static-in-function-g++-aarch64 tls-lib-gcc-aarch64 stb_gnu_unique_tls-aarch64 tls-multiple-module-g++-aarch64 tls-dlopen-gcc-aarch64 call_once-g++-aarch64 tls-thread-g++-aarch64 tls-lib-gcc-without-base-aarch64
for dir in stdcerr-main-gcc extern hello-g++ hello-gcc just-return-g++ just-return-gcc simple-lib-g++ simple-lib-gcc version-gcc tls-lib-gcc tls-lib-gcc-without-base tls-multiple-lib-gcc tls-thread-g++ call_once-g++ inheritance-g++ typeid-g++ dynamic_cast-g++ tls-dlopen-gcc static-in-function-g++ static-in-class-g++ tls-multiple-module-g++ exception-g++ stb_gnu_unique_tls setjmp-gcc tls-bss-gcc tls-bss-g++ hello-g++-aarch64 hello-gcc-aarch64 just-return-g++-aarch64 simple-lib-g++-aarch64 simple-lib-gcc-aarch64 version-gcc-aarch64 tls-bss-gcc-aarch64 tls-bss-g++-aarch64 just-return-gcc-aarch64 setjmp-gcc-aarch64 exception-g++-aarch64 typeid-g++-aarch64 inheritance-g++-aarch64 dynamic_cast-g++-aarch64 static-in-class-g++-aarch64 static-in-function-g++-aarch64 tls-lib-gcc-aarch64 stb_gnu_unique_tls-aarch64 tls-multiple-module-g++-aarch64 tls-dlopen-gcc-aarch64 call_once-g++-aarch64 tls-thread-g++-aarch64 tls-lib-gcc-without-base-aarch64
do
pushd `pwd`
cd $dir
Expand Down
5 changes: 5 additions & 0 deletions feature_unit_tests/stdcerr-main-gcc/hoge.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#include <stdio.h>

void hello_from_hoge() {
fprintf(stderr, "%s:%d hello from stderr\n", __FILE__, __LINE__);
}
9 changes: 9 additions & 0 deletions feature_unit_tests/stdcerr-main-gcc/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#include <stdio.h>

void hello_from_hoge();

int main() {
fprintf(stderr, "%s:%d hello from stderr\n", __FILE__, __LINE__);
hello_from_hoge();
return 0;
}
7 changes: 7 additions & 0 deletions feature_unit_tests/stdcerr-main-gcc/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#! /bin/bash -eux

gcc -o libhoge.so -shared -fpic -fPIC -Wl,-soname,libhoge.so hoge.c
gcc -o main main.c libhoge.so
GLOG_log_dir=. LD_LIBRARY_PATH=. $(git rev-parse --show-toplevel)/build/sold -i main -o main.soldout --section-headers

LD_LIBRARY_PATH=. ./main.soldout
76 changes: 60 additions & 16 deletions sold.cc
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ void Sold::BuildLoads() {

file_offset += phdr->p_vaddr & 0xfff;
load.emit.p_offset = file_offset;
file_offset = AlignNext(file_offset + phdr->p_filesz);
file_offset = AlignNext(file_offset + phdr->p_memsz);
load.emit.p_vaddr += offset;
load.emit.p_paddr += offset;
// TODO(hamaji): Add PF_W only for GOT.
Expand Down Expand Up @@ -279,8 +279,13 @@ void Sold::EmitPhdrs(FILE* fp) {
phdrs.push_back(phdr);
}

for (const Load& load : loads_) {
phdrs.push_back(load.emit);
// I agree this is very bad hack. But I need this to make reloc_copy_ working.
for (int i = 0; i < loads_.size(); i++) {
Elf_Phdr p = loads_[i].emit;
if (i == loads_.size() - 1 || loads_[i].emit.p_vaddr + loads_[i].emit.p_memsz <= loads_[i + 1].emit.p_vaddr) {
p.p_filesz = p.p_memsz;
}
phdrs.emplace_back(p);
}

if (tls_.memsz) {
Expand Down Expand Up @@ -394,7 +399,7 @@ void Sold::DecideMemOffset() {
const Range range = bin->GetRange() + offset;
CHECK(range.start == offset) << "sold cannot handle other than shared objects.";
offsets_.emplace(bin, range.start);
LOG(INFO) << "Assigned: " << bin->soname() << " " << HexString(range.start, 8) << "-" << HexString(range.end, 8);
LOG(INFO) << "Assigned: " << bin->filename() << " " << HexString(range.start, 8) << "-" << HexString(range.end, 8);
offset = range.end;
}
tls_offset_ = offset;
Expand Down Expand Up @@ -477,14 +482,15 @@ uintptr_t Sold::RemapTLS(const char* msg, ELFBinary* bin, uintptr_t off) {
// Push symbols of bin to symtab.
// When the same symbol is already in symtab, LoadDynSymtab selects a more
// concretely defined one.
void Sold::LoadDynSymtab(ELFBinary* bin, std::vector<Syminfo>& symtab) {
void Sold::LoadDynSymtab(ELFBinary* bin, std::vector<Syminfo>& symtab, bool load_defined_syms) {
bin->ReadDynSymtab(filename_to_soname_);

uintptr_t offset = offsets_[bin];

for (const auto& p : bin->GetSymbolMap()) {
const std::string& name = p.name;
Elf_Sym* sym = p.sym;
if (!load_defined_syms && IsDefined(*sym)) continue;
if (IsTLS(*sym) && sym->st_shndx != SHN_UNDEF) {
sym->st_value = RemapTLS("symbol", bin, sym->st_value);
} else if (sym->st_value) {
Expand Down Expand Up @@ -521,6 +527,7 @@ void Sold::LoadDynSymtab(ELFBinary* bin, std::vector<Syminfo>& symtab) {
// Push all global symbols of main_binary_ into public_syms_.
// Push all TLS symbols into public_syms_.
// TODO(akawashiro) Does public_syms_ overlap with exposed_syms_?
// TODO(akawashiro): Is this working?
void Sold::CopyPublicSymbols() {
for (const auto& p : main_binary_->GetSymbolMap()) {
const Elf_Sym* sym = p.sym;
Expand Down Expand Up @@ -591,20 +598,22 @@ void Sold::RelocateSymbol_x86_64(ELFBinary* bin, const Elf_Rel* rel, uintptr_t o
newrels.emplace_back(newrel);
}

LOG(INFO) << "Relocate " << bin->Str(sym->st_name) << " at " << rel->r_offset;
LOG(INFO) << "Relocate " << bin->Str(sym->st_name) << " at " << rel->r_offset << " type=" << ShowRelocationType(type);

for (auto newrel : newrels) {
// Even if we found a defined symbol in src_syms_, we cannot
// erase the relocation entry. The address needs to be fixed at
// runtime by ASLR function so we set RELATIVE to these resolved symbols.
switch (type) {
case R_X86_64_RELATIVE: {
case R_X86_64_RELATIVE:
case R_X86_64_IRELATIVE: {
if (IsDefined(*sym)) {
LOG(WARNING)
<< "The symbol associated with R_X86_64_RELATIVE is defined. Because this relocation type doesn't need any "
"symbol, something wrong may have happened.";
}
newrel.r_addend += offset;
LOG(INFO) << SOLD_LOG_BITS(newrel.r_offset) << SOLD_LOG_BITS(newrel.r_addend);
break;
}

Expand All @@ -614,9 +623,12 @@ void Sold::RelocateSymbol_x86_64(ELFBinary* bin, const Elf_Rel* rel, uintptr_t o
if (syms_.Resolve(bin->Str(sym->st_name), soname, version_name, val_or_index)) {
newrel.r_info = ELF_R_INFO(0, R_X86_64_RELATIVE);
newrel.r_addend = val_or_index;

LOG(INFO) << SOLD_LOG_BITS(newrel.r_offset) << SOLD_LOG_BITS(newrel.r_addend);
} else {
newrel.r_info = ELF_R_INFO(val_or_index, type);
}
LOG(INFO) << SOLD_LOG_BITS(newrel.r_offset) << SOLD_LOG_BITS(newrel.r_addend);
break;
}

Expand All @@ -628,23 +640,24 @@ void Sold::RelocateSymbol_x86_64(ELFBinary* bin, const Elf_Rel* rel, uintptr_t o
} else {
newrel.r_info = ELF_R_INFO(val_or_index, type);
}
LOG(INFO) << SOLD_LOG_BITS(newrel.r_offset) << SOLD_LOG_BITS(newrel.r_addend);
break;
}

// TODO(akawashiro) Handle TLS variables in executables.
case R_X86_64_DTPMOD64: {
// TODO(akawashiro) Refactor out for Arch64
const std::string name = bin->Str(sym->st_name);
uintptr_t index = syms_.ResolveCopy(name, soname, version_name);
uintptr_t index;
syms_.ResolveCopy(name, soname, version_name, &index);
newrel.r_info = ELF_R_INFO(index, type);

if (bin->tls() == NULL) {
LOG(INFO) << SOLD_LOG_64BITS(bin->tls()) << " is null. This relocation is TLS generic dynamic model.";
break;
}

uint64_t* mod_on_got =
reinterpret_cast<uint64_t*>(bin->head_mut() + bin->OffsetFromAddr(rel->r_offset));
uint64_t* mod_on_got = reinterpret_cast<uint64_t*>(bin->head_mut() + bin->OffsetFromAddr(rel->r_offset));
uint64_t* offset_on_got = mod_on_got + 1;
const bool is_bss = bin->IsOffsetInTLSBSS(*offset_on_got);

Expand Down Expand Up @@ -714,7 +727,8 @@ void Sold::RelocateSymbol_x86_64(ELFBinary* bin, const Elf_Rel* rel, uintptr_t o
case R_X86_64_DTPOFF64:
case R_X86_64_TPOFF64: {
const std::string name = bin->Str(sym->st_name);
uintptr_t index = syms_.ResolveCopy(name, soname, version_name);
uintptr_t index;
syms_.ResolveCopy(name, soname, version_name, &index);
newrel.r_info = ELF_R_INFO(index, type);
LOG(INFO) << ShowRelocationType(type) << " relocation: " << SOLD_LOG_KEY(*rel) << SOLD_LOG_KEY(newrel)
<< SOLD_LOG_64BITS(bin->OffsetFromAddr(rel->r_offset));
Expand All @@ -723,8 +737,32 @@ void Sold::RelocateSymbol_x86_64(ELFBinary* bin, const Elf_Rel* rel, uintptr_t o

case R_X86_64_COPY: {
const std::string name = bin->Str(sym->st_name);
uintptr_t index = syms_.ResolveCopy(name, soname, version_name);
newrel.r_info = ELF_R_INFO(index, type);
uintptr_t val_or_index;

bool is_defined = syms_.ResolveCopy(name, soname, version_name, &val_or_index);
if (is_defined && is_executable_) {
const void* reloc_src = nullptr;
for (const ELFBinary* bin : link_binaries_) {
if (bin == main_binary_.get()) continue;
for (int i = 0; i < bin->GetSymbolMap().size(); i++) {
const Syminfo& s = bin->GetSymbolMap()[i];
if (s.name == name && s.soname == soname && s.version == version_name) {
reloc_src = bin->symps()[i];
}
}
}

if (reloc_src != nullptr) {
CHECK(reloc_src != nullptr) << name;
void* reloc_dest = reinterpret_cast<void*>(bin->head_mut() + bin->OffsetFromAddr(rel->r_offset));
reloc_copy_.emplace_back(std::make_tuple(newrel.r_offset, reloc_src, sym->st_size));
goto skip_newrel;
} else {
newrel.r_info = ELF_R_INFO(val_or_index, type);
}
} else {
newrel.r_info = ELF_R_INFO(val_or_index, type);
}
break;
}

Expand All @@ -733,7 +771,10 @@ void Sold::RelocateSymbol_x86_64(ELFBinary* bin, const Elf_Rel* rel, uintptr_t o
CHECK(false);
}

LOG(INFO) << SOLD_LOG_BITS(newrel.r_offset) << SOLD_LOG_BITS(newrel.r_addend) << " " << ShowRelocationType(type) << " "
<< SOLD_LOG_BITS(rel->r_addend) << SOLD_LOG_BITS(rel->r_offset);
rels_.push_back(newrel);
skip_newrel:;
}
}

Expand Down Expand Up @@ -827,7 +868,8 @@ void Sold::RelocateSymbol_aarch64(ELFBinary* bin, const Elf_Rel* rel, uintptr_t
const std::string name = bin->Str(sym->st_name);
if (name == "") {
LOG(INFO) << SOLD_LOG_KEY(name) << "R_AARCH64_TLSDESC in local dynamic";
uintptr_t index = syms_.ResolveCopy(name, soname, version_name);
uintptr_t index;
syms_.ResolveCopy(name, soname, version_name, &index);
newrel.r_info = ELF_R_INFO(index, type);
const bool is_bss = bin->IsOffsetInTLSBSS(newrel.r_addend);
if (is_bss) {
Expand All @@ -842,15 +884,17 @@ void Sold::RelocateSymbol_aarch64(ELFBinary* bin, const Elf_Rel* rel, uintptr_t
break;
} else {
LOG(INFO) << SOLD_LOG_KEY(name) << "R_AARCH64_TLSDESC in generic dynamic";
uintptr_t index = syms_.ResolveCopy(name, soname, version_name);
uintptr_t index;
syms_.ResolveCopy(name, soname, version_name, &index);
newrel.r_info = ELF_R_INFO(index, type);
break;
}
}

case R_AARCH64_COPY: {
const std::string name = bin->Str(sym->st_name);
uintptr_t index = syms_.ResolveCopy(name, soname, version_name);
uintptr_t index;
syms_.ResolveCopy(name, soname, version_name, &index);
newrel.r_info = ELF_R_INFO(index, type);
break;
}
Expand Down
Loading