diff options
-rw-r--r-- | scripts/check-localplt.awk | 40 | ||||
-rw-r--r-- | scripts/localplt.awk | 47 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/i386/localplt.data | 8 | ||||
-rw-r--r-- | sysdeps/x86_64/localplt.data | 19 |
4 files changed, 106 insertions, 8 deletions
diff --git a/scripts/check-localplt.awk b/scripts/check-localplt.awk index bb1b912131..3965292888 100644 --- a/scripts/check-localplt.awk +++ b/scripts/check-localplt.awk @@ -3,9 +3,14 @@ # Each line is either a comment starting with # or it looks like: # libfoo.so: function # or +# libfoo.so: function + {RELA|REL} RELOC +# or # libfoo.so: function ? -# The latter means that a PLT entry for function is optional in libfoo.so. -# The former means one is required. +# The first entry means that one is required. +# The second entry means that one is required and relocation may also be +# {RELA|REL} RELOC. +# The third entry means that a PLT entry for function is optional in +# libfoo.so. # The second file argument is - and this (stdin) receives the output # of the check-localplt program. @@ -14,7 +19,10 @@ BEGIN { result = 0 } FILENAME != "-" && /^#/ { next } FILENAME != "-" { - if (NF != 2 && !(NF == 3 && $3 == "?")) { + if (NF == 5 && $3 == "+" && ($4 == "RELA" || $4 == "REL")) { + accept_type[$1 " " $2] = $4; + accept_reloc[$1 " " $2] = $5; + } else if (NF != 2 && !(NF == 3 && $3 == "?")) { printf "%s:%d: bad data line: %s\n", FILENAME, FNR, $0 > "/dev/stderr"; result = 2; } else { @@ -23,7 +31,7 @@ FILENAME != "-" { next; } -NF != 2 { +NF != 2 && !(NF == 4 && ($3 == "RELA" || $3 == "REL")) { print "Unexpected output from check-localplt:", $0 > "/dev/stderr"; result = 2; next @@ -31,7 +39,23 @@ NF != 2 { { key = $1 " " $2 - if (key in accept) { + if ($3 == "RELA" || $3 == "REL") { + # Entries like: + # libc.so: free + RELA R_X86_64_GLOB_DAT + # may be ignored. + if (key in accept_type && accept_type[key] == $3 && accept_reloc[key] == $4) { + # Match + # libc.so: free + RELA R_X86_64_GLOB_DAT + delete accept_type[key] + } + } else if (NF == 2 && key in accept_reloc) { + # Match + # libc.so: free + # against + # libc.so: free + RELA R_X86_64_GLOB_DAT + if (key in accept_type) + delete accept_type[key] + } else if (key in accept) { delete accept[key] } else { print "Extra PLT reference:", $0; @@ -49,5 +73,11 @@ END { } } + for (key in accept_type) { + # It's mandatory. + print "Missing required PLT or " accept_reloc[key] " reference:", key; + result = 1; + } + exit(result); } diff --git a/scripts/localplt.awk b/scripts/localplt.awk index 84c94d1024..f75b3b427b 100644 --- a/scripts/localplt.awk +++ b/scripts/localplt.awk @@ -13,6 +13,8 @@ FILENAME != lastfile { } lastfile = FILENAME; jmprel_offset = 0; + rela_offset = 0; + rel_offset = 0; delete section_offset_by_address; } @@ -43,6 +45,30 @@ in_relocs && relocs_offset == jmprel_offset && NF >= 5 { } } +in_relocs && relocs_offset == rela_offset && NF >= 5 { + # Relocations against GNU_IFUNC symbols are not shown as an hexadecimal + # value, but rather as the resolver symbol followed by (). + if ($4 ~ /\(\)/) { + print whatfile, gensub(/@.*/, "", "g", $5), "RELA", $3 + } else { + symval = strtonum("0x" $4); + if (symval != 0) + print whatfile, gensub(/@.*/, "", "g", $5), "RELA", $3 + } +} + +in_relocs && relocs_offset == rel_offset && NF >= 5 { + # Relocations against GNU_IFUNC symbols are not shown as an hexadecimal + # value, but rather as the resolver symbol followed by (). + if ($4 ~ /\(\)/) { + print whatfile, gensub(/@.*/, "", "g", $5), "REL", $3 + } else { + symval = strtonum("0x" $4); + if (symval != 0) + print whatfile, gensub(/@.*/, "", "g", $5), "REL", $3 + } +} + in_relocs { next } $1 == "Relocation" && $2 == "section" && $5 == "offset" { @@ -62,4 +88,25 @@ $2 == "(JMPREL)" { next } +$2 == "(RELA)" { + rela_addr = strtonum($3); + if (rela_addr in section_offset_by_address) { + rela_offset = section_offset_by_address[rela_addr]; + } else { + print FILENAME ": *** DT_RELA does not match any section's address"; + result = 2; + } + next +} + +$2 == "(REL)" { + rel_addr = strtonum($3); + if (rel_addr in section_offset_by_address) { + rel_offset = section_offset_by_address[rel_addr]; + } else { + print FILENAME ": *** DT_REL does not match any section's address"; + result = 2; + } + next +} END { exit(result) } diff --git a/sysdeps/unix/sysv/linux/i386/localplt.data b/sysdeps/unix/sysv/linux/i386/localplt.data index b25abf8006..2e03821dfd 100644 --- a/sysdeps/unix/sysv/linux/i386/localplt.data +++ b/sysdeps/unix/sysv/linux/i386/localplt.data @@ -1,7 +1,9 @@ +# Linker in binutils 2.26 and newer consolidates R_X86_64_JUMP_SLOT +# relocation with R_386_GLOB_DAT relocation against the same symbol. libc.so: _Unwind_Find_FDE libc.so: calloc -libc.so: free -libc.so: malloc +libc.so: free + REL R_386_GLOB_DAT +libc.so: malloc + REL R_386_GLOB_DAT libc.so: memalign libc.so: realloc libm.so: matherr @@ -12,4 +14,4 @@ ld.so: __libc_memalign ld.so: malloc ld.so: calloc ld.so: realloc -ld.so: free +ld.so: free + REL R_386_GLOB_DAT diff --git a/sysdeps/x86_64/localplt.data b/sysdeps/x86_64/localplt.data new file mode 100644 index 0000000000..d140476dfe --- /dev/null +++ b/sysdeps/x86_64/localplt.data @@ -0,0 +1,19 @@ +# See scripts/check-localplt.awk for how this file is processed. +# PLT use is required for the malloc family and for matherr because +# users can define their own functions and have library internals call them. +# Linker in binutils 2.26 and newer consolidates R_X86_64_JUMP_SLOT +# relocation with R_X86_64_GLOB_DAT relocation against the same symbol. +libc.so: calloc +libc.so: free + RELA R_X86_64_GLOB_DAT +libc.so: malloc + RELA R_X86_64_GLOB_DAT +libc.so: memalign +libc.so: realloc +libm.so: matherr +# The dynamic loader uses __libc_memalign internally to allocate aligned +# TLS storage. The other malloc family of functions are expected to allow +# user symbol interposition. +ld.so: __libc_memalign +ld.so: malloc +ld.so: calloc +ld.so: realloc +ld.so: free + RELA R_X86_64_GLOB_DAT |