summaryrefslogtreecommitdiffstats
path: root/binutils-2.25/gold/testsuite/relro_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'binutils-2.25/gold/testsuite/relro_test.cc')
-rw-r--r--binutils-2.25/gold/testsuite/relro_test.cc160
1 files changed, 160 insertions, 0 deletions
diff --git a/binutils-2.25/gold/testsuite/relro_test.cc b/binutils-2.25/gold/testsuite/relro_test.cc
new file mode 100644
index 00000000..795ad391
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/relro_test.cc
@@ -0,0 +1,160 @@
+// relro_test.cc -- test -z relro for gold
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+#include <cassert>
+#include <csignal>
+#include <cstdio>
+#include <cstdlib>
+#include <exception>
+#include <stdint.h>
+#include <unistd.h>
+
+// This tests we were linked with a script. If we were linked with a
+// script, relro currently does not work.
+
+extern char using_script[] __attribute__ ((weak));
+
+// This code is put into a shared library linked with -z relro.
+
+// i1 and i2 are not relro variables.
+int i1 = 1;
+static int i2 = 2;
+
+// P1 is a global relro variable.
+int* const p1 __attribute__ ((aligned(64))) = &i1;
+
+// P2 is a local relro variable.
+int* const p2 __attribute__ ((aligned(64))) = &i2;
+
+// Add a TLS variable to make sure -z relro works correctly with TLS.
+__thread int i3 = 1;
+
+// Test symbol addresses.
+
+bool
+t1()
+{
+ if (using_script)
+ return true;
+
+ void* i1addr = static_cast<void*>(&i1);
+ void* i2addr = static_cast<void*>(&i2);
+ const void* p1addr = static_cast<const void*>(&p1);
+ const void* p2addr = static_cast<const void*>(&p2);
+
+ // The relro variables should precede the non-relro variables in the
+ // memory image.
+ assert(i1addr > p1addr);
+ assert(i1addr > p2addr);
+ assert(i2addr > p1addr);
+ assert(i2addr > p2addr);
+
+ // The relro variables should not be on the same page as the
+ // non-relro variables.
+ const size_t page_size = getpagesize();
+ uintptr_t i1page = reinterpret_cast<uintptr_t>(i1addr) & ~ (page_size - 1);
+ uintptr_t i2page = reinterpret_cast<uintptr_t>(i2addr) & ~ (page_size - 1);
+ uintptr_t p1page = reinterpret_cast<uintptr_t>(p1addr) & ~ (page_size - 1);
+ uintptr_t p2page = reinterpret_cast<uintptr_t>(p2addr) & ~ (page_size - 1);
+ assert(i1page != p1page);
+ assert(i1page != p2page);
+ assert(i2page != p1page);
+ assert(i2page != p2page);
+ assert(i3 == 1);
+
+ return true;
+}
+
+// Tell terminate handler that we are throwing from a signal handler.
+
+static bool throwing;
+
+// A signal handler for SIGSEGV.
+
+extern "C"
+void
+sigsegv_handler(int)
+{
+ throwing = true;
+ throw 0;
+}
+
+// The original terminate handler.
+
+std::terminate_handler orig_terminate;
+
+// Throwing an exception out of a signal handler doesn't always work
+// reliably. When that happens the program will call terminate. We
+// set a terminate handler to indicate that the test probably passed.
+
+void
+terminate_handler()
+{
+ if (!throwing)
+ {
+ orig_terminate();
+ ::exit(EXIT_FAILURE);
+ }
+ fprintf(stderr,
+ "relro_test: terminate called due to failure to throw through signal handler\n");
+ fprintf(stderr, "relro_test: assuming test succeeded\n");
+ ::exit(EXIT_SUCCESS);
+}
+
+// Use a separate function to throw the exception, so that we don't
+// need to use -fnon-call-exceptions.
+
+void f2() __attribute__ ((noinline));
+void
+f2()
+{
+ int** pp1 = const_cast<int**>(&p1);
+ *pp1 = &i2;
+
+ // We shouldn't get here--the assignment to *pp1 should write to
+ // memory which the dynamic linker marked as read-only, giving us a
+ // SIGSEGV, causing sigsegv_handler to be invoked, to throw past us.
+ assert(0);
+}
+
+// Changing a relro variable should give us a SIGSEGV.
+
+bool
+t2()
+{
+ if (using_script)
+ return true;
+
+ signal(SIGSEGV, sigsegv_handler);
+ orig_terminate = std::set_terminate(terminate_handler);
+
+ try
+ {
+ f2();
+ return false;
+ }
+ catch (int i)
+ {
+ assert(i == 0);
+ return true;
+ }
+}