X-Git-Url: https://oss.titaniummirror.com/gitweb?p=msp430-binutils.git;a=blobdiff_plain;f=gold%2Ftestsuite%2Frelro_test.cc;fp=gold%2Ftestsuite%2Frelro_test.cc;h=bc6c77b91ebeb8aae810aeacca72d5f6f3cf4a59;hp=0000000000000000000000000000000000000000;hb=88750007d7869f178f0ba528f41efd3b74c424cf;hpb=6df9443a374e2b81278c61b8afc0a1eef7db280b diff --git a/gold/testsuite/relro_test.cc b/gold/testsuite/relro_test.cc new file mode 100644 index 0000000..bc6c77b --- /dev/null +++ b/gold/testsuite/relro_test.cc @@ -0,0 +1,156 @@ +// relro_test.cc -- test -z relro for gold + +// Copyright 2008 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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 +#include +#include +#include +#include +#include +#include + +// 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 = &i1; + +// P2 is a local relro variable. +int* const p2 = &i2; + +// Test symbol addresses. + +bool +t1() +{ + if (using_script) + return true; + + void* i1addr = static_cast(&i1); + void* i2addr = static_cast(&i2); + const void* p1addr = static_cast(&p1); + const void* p2addr = static_cast(&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(i1addr) & ~ (page_size - 1); + uintptr_t i2page = reinterpret_cast(i2addr) & ~ (page_size - 1); + uintptr_t p1page = reinterpret_cast(p1addr) & ~ (page_size - 1); + uintptr_t p2page = reinterpret_cast(p2addr) & ~ (page_size - 1); + assert(i1page != p1page); + assert(i1page != p2page); + assert(i2page != p1page); + assert(i2page != p2page); + + 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(&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; + } +}