Track protos + globals w/out initializers as undef too (not just helper funcs)
Also handle empty global variable lists -- and initialize
ShAddralign to 1 instead of 0, just in case. Previously
it would try to align by 0 when the variable list was empty.
This should help the crosstests pass with --elf.
BUG=none
R=kschimpf@google.com, stichnot@chromium.org
Review URL: https://codereview.chromium.org/899483002
diff --git a/src/IceConverter.cpp b/src/IceConverter.cpp
index 47f8b39..5316db6 100644
--- a/src/IceConverter.cpp
+++ b/src/IceConverter.cpp
@@ -121,9 +121,20 @@
Ice::Constant *convertConstant(const Constant *Const) {
if (const auto GV = dyn_cast<GlobalValue>(Const)) {
Ice::GlobalDeclaration *Decl = getConverter().getGlobalDeclaration(GV);
- const Ice::RelocOffsetT Offset = 0;
- return Ctx->getConstantSym(Offset, Decl->getName(),
- Decl->getSuppressMangling());
+ bool IsUndefined = false;
+ if (const auto *Func = llvm::dyn_cast<Ice::FunctionDeclaration>(Decl))
+ IsUndefined = Func->isProto();
+ else if (const auto *Var = llvm::dyn_cast<Ice::VariableDeclaration>(Decl))
+ IsUndefined = !Var->hasInitializer();
+ else
+ report_fatal_error("Unhandled GlobalDeclaration type");
+ if (IsUndefined)
+ return Ctx->getConstantExternSym(Decl->getName());
+ else {
+ const Ice::RelocOffsetT Offset = 0;
+ return Ctx->getConstantSym(Offset, Decl->getName(),
+ Decl->getSuppressMangling());
+ }
} else if (const auto CI = dyn_cast<ConstantInt>(Const)) {
Ice::Type Ty = convertToIceType(CI->getType());
return Ctx->getConstantInt(Ty, CI->getSExtValue());
diff --git a/src/IceELFObjectWriter.cpp b/src/IceELFObjectWriter.cpp
index c428c12..2d11eb3 100644
--- a/src/IceELFObjectWriter.cpp
+++ b/src/IceELFObjectWriter.cpp
@@ -308,11 +308,13 @@
void ELFObjectWriter::writeDataOfType(SectionType ST,
const VariableDeclarationList &Vars,
FixupKind RelocationKind, bool IsELF64) {
+ if (Vars.empty())
+ return;
ELFDataSection *Section;
ELFRelocationSection *RelSection;
// TODO(jvoung): Handle fdata-sections.
IceString SectionName;
- Elf64_Xword ShAddralign = 0;
+ Elf64_Xword ShAddralign = 1;
for (VariableDeclaration *Var : Vars) {
Elf64_Xword Align = Var->getAlignment();
ShAddralign = std::max(ShAddralign, Align);
@@ -362,6 +364,10 @@
const uint8_t SymbolType = STT_OBJECT;
for (VariableDeclaration *Var : Vars) {
+ // If the variable declaration does not have an initializer, its symtab
+ // entry will be created separately.
+ if (!Var->hasInitializer())
+ continue;
Elf64_Xword Align = Var->getAlignment();
Section->padToAlignment(Str, Align);
SizeT SymbolSize = Var->getNumBytes();
diff --git a/src/PNaClTranslator.cpp b/src/PNaClTranslator.cpp
index 249875f..4d83578 100644
--- a/src/PNaClTranslator.cpp
+++ b/src/PNaClTranslator.cpp
@@ -284,10 +284,15 @@
// TODO(kschimpf) Don't get addresses of intrinsic function declarations.
Ice::GlobalDeclaration *Decl = nullptr;
unsigned FcnIDSize = FunctionDeclarationList.size();
+ bool IsUndefined = false;
if (ID < FcnIDSize) {
Decl = FunctionDeclarationList[ID];
+ const auto Func = llvm::cast<Ice::FunctionDeclaration>(Decl);
+ IsUndefined = Func->isProto();
} else if ((ID - FcnIDSize) < VariableDeclarations.size()) {
Decl = VariableDeclarations[ID - FcnIDSize];
+ const auto Var = llvm::cast<Ice::VariableDeclaration>(Decl);
+ IsUndefined = !Var->hasInitializer();
}
std::string Name;
bool SuppressMangling;
@@ -303,9 +308,13 @@
Name = "??";
SuppressMangling = false;
}
- const Ice::RelocOffsetT Offset = 0;
- C = getTranslator().getContext()->getConstantSym(Offset, Name,
- SuppressMangling);
+ if (IsUndefined)
+ C = getTranslator().getContext()->getConstantExternSym(Name);
+ else {
+ const Ice::RelocOffsetT Offset = 0;
+ C = getTranslator().getContext()->getConstantSym(Offset, Name,
+ SuppressMangling);
+ }
ValueIDConstants[ID] = C;
return C;
}
diff --git a/tests_lit/llvm2ice_tests/elf_container.ll b/tests_lit/llvm2ice_tests/elf_container.ll
index d8b6ad0..125be2c 100644
--- a/tests_lit/llvm2ice_tests/elf_container.ll
+++ b/tests_lit/llvm2ice_tests/elf_container.ll
@@ -21,6 +21,11 @@
declare void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i32, i1)
declare void @llvm.memset.p0i8.i32(i8*, i8, i32, i32, i1)
+; Try other external functions (for cross tests).
+; Not testing external global variables since the NaCl bitcode writer
+; refuses to freeze such IR.
+declare void @external_foo(i32)
+
; Test some global data relocs (data, rodata, bss).
@bytes = internal global [7 x i8] c"ab\03\FF\F6fg", align 1
@bytes_const = internal constant [7 x i8] c"ab\03\FF\F6fg", align 1
@@ -97,6 +102,12 @@
ret float %f
}
+; Test calling an external function.
+define internal void @test_call_external() {
+ call void @external_foo(i32 42)
+ ret void
+}
+
; Test copying a function pointer, or a global data pointer.
define internal i32 @test_ret_fp() {
%r = ptrtoint float ()* @returnFloatConst to i32
@@ -387,6 +398,7 @@
; CHECK: 0x34 R_386_32 .L$double$2 0x0
; CHECK: 0x{{.*}} R_386_PC32 memcpy
; CHECK: 0x{{.*}} R_386_PC32 memset
+; CHECK: 0x{{.*}} R_386_PC32 external_foo
; CHECK: }
; CHECK: Section ({{[0-9]+}}) .rel.data {
; The set of relocations between llvm-mc and the integrated elf-writer
@@ -614,6 +626,15 @@
; CHECK-NEXT: Section: .text
; CHECK-NEXT: }
; CHECK: Symbol {
+; CHECK: Name: external_foo
+; CHECK-NEXT: Value: 0x0
+; CHECK-NEXT: Size: 0
+; CHECK-NEXT: Binding: Global
+; CHECK-NEXT: Type: None
+; CHECK-NEXT: Other: 0
+; CHECK-NEXT: Section: Undefined
+; CHECK-NEXT: }
+; CHECK: Symbol {
; CHECK: Name: memcpy
; CHECK-NEXT: Value: 0x0
; CHECK-NEXT: Size: 0
diff --git a/tests_lit/llvm2ice_tests/elf_nodata.ll b/tests_lit/llvm2ice_tests/elf_nodata.ll
new file mode 100644
index 0000000..8170676
--- /dev/null
+++ b/tests_lit/llvm2ice_tests/elf_nodata.ll
@@ -0,0 +1,127 @@
+; Tests that we generate an ELF container correctly when there
+; is no data section.
+
+; For the integrated ELF writer, we can't pipe the output because we need
+; to seek backward and patch up the file headers. So, use a temporary file.
+; RUN: %p2i -i %s --args -O2 --verbose none -elf-writer -o %t \
+; RUN: && llvm-readobj -file-headers -sections -section-data \
+; RUN: -relocations -symbols %t | FileCheck %s
+
+; RUN: %p2i -i %s --args -O2 --verbose none \
+; RUN: | llvm-mc -triple=i686-none-nacl -filetype=obj -o - \
+; RUN: | llvm-readobj -file-headers -sections -section-data \
+; RUN: -relocations -symbols - | FileCheck %s
+
+declare void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i32, i1)
+
+define internal i32 @foo(i32 %x, i32 %len) {
+ %y = add i32 %x, %x
+ %dst = inttoptr i32 %y to i8*
+ %src = inttoptr i32 %x to i8*
+ call void @llvm.memcpy.p0i8.p0i8.i32(i8* %dst, i8* %src,
+ i32 %len, i32 1, i1 false)
+
+ ret i32 %y
+}
+
+; Test defining a non-internal function.
+define void @_start(i32 %x) {
+ %ignored = call i32 @foo(i32 %x, i32 4)
+ ret void
+}
+
+; CHECK: Section {
+; CHECK: Index: {{[1-9][0-9]*}}
+; CHECK: Name: .text
+; CHECK: Type: SHT_PROGBITS
+; CHECK: Flags [ (0x6)
+; CHECK: SHF_ALLOC
+; CHECK: SHF_EXECINSTR
+; CHECK: ]
+; CHECK: Address: 0x0
+; CHECK: Offset: 0x{{[1-9A-F][0-9A-F]*}}
+; CHECK: Size: {{[1-9][0-9]*}}
+; CHECK: Link: 0
+; CHECK: Info: 0
+; CHECK: AddressAlignment: 32
+; CHECK: EntrySize: 0
+; CHECK: SectionData (
+; CHECK: )
+; CHECK: }
+; CHECK: Section {
+; CHECK: Index: {{[1-9][0-9]*}}
+; CHECK: Name: .rel.text
+; CHECK: Type: SHT_REL
+; CHECK: Flags [ (0x0)
+; CHECK: ]
+; CHECK: Address: 0x0
+; CHECK: Offset: 0x{{[1-9A-F][0-9A-F]*}}
+; CHECK: Size: {{[1-9][0-9]*}}
+; CHECK: Link: [[SYMTAB_INDEX:[1-9][0-9]*]]
+; CHECK: Info: {{[1-9][0-9]*}}
+; CHECK: AddressAlignment: 4
+; CHECK: EntrySize: 8
+; CHECK: SectionData (
+; CHECK: )
+; CHECK: }
+; CHECK: Section {
+; CHECK: Index: [[SYMTAB_INDEX]]
+; CHECK-NEXT: Name: .symtab
+; CHECK: Type: SHT_SYMTAB
+; CHECK: Flags [ (0x0)
+; CHECK: ]
+; CHECK: Address: 0x0
+; CHECK: Offset: 0x{{[1-9A-F][0-9A-F]*}}
+; CHECK: Size: {{[1-9][0-9]*}}
+; CHECK: Link: {{[1-9][0-9]*}}
+; CHECK: Info: {{[1-9][0-9]*}}
+; CHECK: AddressAlignment: 4
+; CHECK: EntrySize: 16
+; CHECK: }
+
+
+; CHECK: Relocations [
+; CHECK: Section ({{[0-9]+}}) .rel.text {
+; CHECK: 0x21 R_386_PC32 memcpy 0x0
+; CHECK: }
+; CHECK: ]
+
+
+; CHECK: Symbols [
+; CHECK-NEXT: Symbol {
+; CHECK-NEXT: Name: (0)
+; CHECK-NEXT: Value: 0x0
+; CHECK-NEXT: Size: 0
+; CHECK-NEXT: Binding: Local
+; CHECK-NEXT: Type: None
+; CHECK-NEXT: Other: 0
+; CHECK-NEXT: Section: Undefined (0x0)
+; CHECK-NEXT: }
+; CHECK: Symbol {
+; CHECK: Name: foo
+; CHECK-NEXT: Value: 0x0
+; CHECK-NEXT: Size: 0
+; CHECK-NEXT: Binding: Local
+; CHECK-NEXT: Type: None
+; CHECK-NEXT: Other: 0
+; CHECK-NEXT: Section: .text
+; CHECK-NEXT: }
+; CHECK: Symbol {
+; CHECK: Name: _start
+; CHECK-NEXT: Value: 0x{{[1-9A-F][0-9A-F]*}}
+; CHECK-NEXT: Size: 0
+; CHECK-NEXT: Binding: Global
+; CHECK-NEXT: Type: Function
+; CHECK-NEXT: Other: 0
+; CHECK-NEXT: Section: .text
+; CHECK-NEXT: }
+; CHECK: Symbol {
+; CHECK: Name: memcpy
+; CHECK-NEXT: Value: 0x0
+; CHECK-NEXT: Size: 0
+; CHECK-NEXT: Binding: Global
+; CHECK-NEXT: Type: None
+; CHECK-NEXT: Other: 0
+; CHECK-NEXT: Section: Undefined
+; CHECK-NEXT: }
+; CHECK: ]