versions.awk 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. # Combine version map fragments into version scripts for our shared objects.
  2. # Copyright (C) 1998-2026 Free Software Foundation, Inc.
  3. # This script expects the following variables to be defined:
  4. # defsfile name of Versions.def file
  5. # buildroot name of build directory with trailing slash
  6. # move_if_change move-if-change command
  7. # Read definitions for the versions.
  8. BEGIN {
  9. lossage = 0;
  10. nlibs=0;
  11. while (getline < defsfile) {
  12. if (/^[a-zA-Z0-9_.]+ \{/) {
  13. libs[$1] = 1;
  14. curlib = $1;
  15. while (getline < defsfile && ! /^}/) {
  16. if ($2 == "=") {
  17. renamed[curlib "::" $1] = $3;
  18. }
  19. else
  20. versions[curlib "::" $1] = 1;
  21. }
  22. }
  23. }
  24. close(defsfile);
  25. tmpfile = buildroot "Versions.tmp";
  26. # POSIX sort needed.
  27. sort = "sort -t. -k 1,1 -k 2n,2n -k 3 > " tmpfile;
  28. }
  29. # GNU awk does not implement the ord and chr functions.
  30. # <https://www.gnu.org/software/gawk/manual/html_node/Ordinal-Functions.html>
  31. # says that they are "written very nicely", using code similar to what
  32. # is included here.
  33. function chr(c) {
  34. return sprintf("%c", c)
  35. }
  36. BEGIN {
  37. for (c = 1; c < 127; c++) {
  38. ord_table[chr(c)] = c;
  39. }
  40. }
  41. function ord(c) {
  42. if (ord_table[c]) {
  43. return ord_table[c];
  44. } else {
  45. printf("Invalid character reference: '%c'\n", c) > "/dev/stderr";
  46. ++lossage;
  47. }
  48. }
  49. # Remove comment lines.
  50. /^ *#/ {
  51. next;
  52. }
  53. # This matches the beginning of the version information for a new library.
  54. /^[a-zA-Z0-9_.]+/ {
  55. actlib = $1;
  56. if (!libs[$1]) {
  57. printf("no versions defined for %s\n", $1) > "/dev/stderr";
  58. ++lossage;
  59. }
  60. next;
  61. }
  62. # This matches the beginning of a new version for the current library.
  63. /^ [A-Za-z_]/ {
  64. if (renamed[actlib "::" $1])
  65. actver = renamed[actlib "::" $1];
  66. else if (!versions[actlib "::" $1] && $1 != "GLIBC_PRIVATE") {
  67. printf("version %s not defined for %s\n", $1, actlib) > "/dev/stderr";
  68. ++lossage;
  69. }
  70. else
  71. actver = $1;
  72. next;
  73. }
  74. # This matches lines with names to be added to the current version in the
  75. # current library. This is the only place where we print something to
  76. # the intermediate file.
  77. /^ / {
  78. sortver=actver
  79. # Ensure GLIBC_ versions come always first
  80. sub(/^GLIBC_/," GLIBC_",sortver)
  81. printf("%s %s %s\n", actlib, sortver, $0) | sort;
  82. }
  83. # Some targets do not set the ABI baseline for libdl. As a result,
  84. # symbols originally in libdl need to be moved under historic symbol
  85. # versions, without altering the baseline version for libc itself.
  86. /^ *!libc_pre_versions/ {
  87. libc_pre_versions_active = 1;
  88. }
  89. function libc_pre_versions() {
  90. # No local: * here, so that we do not have to update this script
  91. # if symbols are moved into libc. The abilist files and the other
  92. # targets (with a real GLIBC_2.0 baseline) provide testing
  93. # coverage.
  94. printf("\
  95. GLIBC_2.0 {\n\
  96. };\n\
  97. GLIBC_2.1 {\n\
  98. } GLIBC_2.0;\n\
  99. ") > outfile;
  100. return "GLIBC_2.1";
  101. }
  102. function closeversion(name, oldname) {
  103. printf(" local:\n *;\n") > outfile;
  104. # This version inherits from the last one only if they
  105. # have the same nonnumeric prefix, i.e. GLIBC_x.y and GLIBC_x.z
  106. # or FOO_x and FOO_y but not GLIBC_x and FOO_y.
  107. pfx = oldname;
  108. sub(/[0-9.]+/,".+",pfx);
  109. if (oldname == "" || name !~ pfx) print "};" > outfile;
  110. else printf("} %s;\n", oldname) > outfile;
  111. }
  112. function close_and_move(name, real_name) {
  113. close(name);
  114. system(move_if_change " " name " " real_name " >&2");
  115. }
  116. # ELF hash, for use with symbol versions.
  117. function elf_hash(s, i, acc) {
  118. acc = 0;
  119. for (i = 1; i <= length(s); ++i) {
  120. acc = and(lshift(acc, 4) + ord(substr(s, i, 1)), 0xffffffff);
  121. top = and(acc, 0xf0000000);
  122. acc = and(xor(acc, rshift(top, 24)), compl(top));
  123. }
  124. return acc;
  125. }
  126. # Now print the accumulated information.
  127. END {
  128. close(sort);
  129. if (lossage) {
  130. system("rm -f " tmpfile);
  131. exit 1;
  132. }
  133. oldlib = "";
  134. oldver = "";
  135. real_first_ver_header = buildroot "first-versions.h"
  136. first_ver_header = real_first_ver_header "T"
  137. printf("#ifndef _FIRST_VERSIONS_H\n") > first_ver_header;
  138. printf("#define _FIRST_VERSIONS_H\n") > first_ver_header;
  139. real_ldbl_compat_header = buildroot "ldbl-compat-choose.h"
  140. ldbl_compat_header = real_ldbl_compat_header "T"
  141. printf("#ifndef _LDBL_COMPAT_CHOOSE_H\n") > ldbl_compat_header;
  142. printf("#define _LDBL_COMPAT_CHOOSE_H\n") > ldbl_compat_header;
  143. printf("#ifndef LONG_DOUBLE_COMPAT\n") > ldbl_compat_header;
  144. printf("# error LONG_DOUBLE_COMPAT not defined\n") > ldbl_compat_header;
  145. printf("#endif\n") > ldbl_compat_header;
  146. printf("version-maps =");
  147. while (getline < tmpfile) {
  148. if ($1 != oldlib) {
  149. if (oldlib != "") {
  150. closeversion(oldver, veryoldver);
  151. oldver = "";
  152. close_and_move(outfile, real_outfile);
  153. }
  154. oldlib = $1;
  155. real_outfile = buildroot oldlib ".map";
  156. outfile = real_outfile "T";
  157. if ($1 == "libc" && libc_pre_versions_active) {
  158. veryoldver = libc_pre_versions();
  159. } else {
  160. veryoldver = "";
  161. }
  162. printf(" %s.map", oldlib);
  163. }
  164. if ($2 != oldver) {
  165. if (oldver != "") {
  166. closeversion(oldver, veryoldver);
  167. veryoldver = oldver;
  168. }
  169. oldver = $2;
  170. # Skip the placeholder symbol used only for empty version map.
  171. if ($3 == "__placeholder_only_for_empty_version_map;") {
  172. printf("%s {\n", $2) > outfile;
  173. continue;
  174. }
  175. printf("%s {\n global:\n", $2) > outfile;
  176. }
  177. printf(" ") > outfile;
  178. for (n = 3; n <= NF; ++n) {
  179. printf(" %s", $n) > outfile;
  180. sym = $n;
  181. sub(";", "", sym);
  182. first_ver_macro = "FIRST_VERSION_" oldlib "_" sym;
  183. if (!(first_ver_macro in first_ver_seen) \
  184. && oldver ~ "^GLIBC_[0-9]" \
  185. && sym ~ "^[A-Za-z0-9_]*$") {
  186. ver_val = oldver;
  187. printf("#define %s_STRING \"%s\"\n", first_ver_macro, ver_val) > first_ver_header;
  188. printf("#define %s_HASH 0x%x\n", first_ver_macro, elf_hash(ver_val)) > first_ver_header;
  189. gsub("\\.", "_", ver_val);
  190. printf("#define %s %s\n", first_ver_macro, ver_val) > first_ver_header;
  191. first_ver_seen[first_ver_macro] = 1;
  192. if (oldlib == "libc" || oldlib == "libm") {
  193. printf("#if LONG_DOUBLE_COMPAT (%s, %s)\n",
  194. oldlib, ver_val) > ldbl_compat_header;
  195. printf("# define LONG_DOUBLE_COMPAT_CHOOSE_%s_%s(a, b) a\n",
  196. oldlib, sym) > ldbl_compat_header;
  197. printf("#else\n") > ldbl_compat_header;
  198. printf("# define LONG_DOUBLE_COMPAT_CHOOSE_%s_%s(a, b) b\n",
  199. oldlib, sym) > ldbl_compat_header;
  200. printf("#endif\n") > ldbl_compat_header;
  201. }
  202. }
  203. }
  204. printf("\n") > outfile;
  205. }
  206. printf("\n");
  207. printf("#endif /* first-versions.h */\n") > first_ver_header;
  208. printf("#endif /* ldbl-compat-choose.h */\n") > ldbl_compat_header;
  209. closeversion(oldver, veryoldver);
  210. close_and_move(outfile, real_outfile);
  211. close_and_move(first_ver_header, real_first_ver_header);
  212. close_and_move(ldbl_compat_header, real_ldbl_compat_header);
  213. #system("rm -f " tmpfile);
  214. }