diff options
| author | Po Lu | 2025-03-09 23:02:21 +0800 |
|---|---|---|
| committer | Po Lu | 2025-03-09 23:07:33 +0800 |
| commit | a5f8ce9f1eae29f87fe13adb61bd4e15faa628a2 (patch) | |
| tree | 602dba32bf3efcd7743f0d2df5e73339d98a5b2e /src/pdumper.c | |
| parent | 57cef07710d91988b6332ad3ed2f5c4b4b371585 (diff) | |
| download | emacs-a5f8ce9f1eae29f87fe13adb61bd4e15faa628a2.tar.gz emacs-a5f8ce9f1eae29f87fe13adb61bd4e15faa628a2.zip | |
Re-port to 32-bit systems without alignment primitives
* configure.ac (ALIGNOF_INT, ALIGNOF_LONG, ALIGNOF_LONG_LONG):
New variables.
(emacs_cv_alignas_unavailable): Define if alignas and structure
alignment primitives are unavailable. In such an environment,
the MSB tagging scheme must be enabled, as must the GNU malloc.
* msdos/sed2v2.inp: Adjust correspondingly.
* src/alloc.c (union emacs_align_type): Remove types which
contain flexible array members. The address of a field
subsequent to an aggregate with flexible array members cannot
validly be taken.
(mark_memory) [!USE_LSB_TAG && !WIDE_EMACS_INT]: Strip type bits
before scanning memory.
* src/emacs.c (main):
* src/eval.c (Fautoload_do_load):
* src/fns.c (Frequire): Rename a number of illogically named
fields.
* src/lisp.h (ALIGNOF_EMACS_INT): Define to the natural
alignment of EMACS_INT.
(IDEAL_GCALIGNMENT): New macro.
(USE_LSB_TAG): Disable if no alignment specifiers are available,
WIDE_EMACS_INT is undefined, and the natural alignment of
EMACS_INT falls short of LSB tagging's requirements.
(gflags): Rename illogically named fields and don't define them
as bitfields, which runs afoul of certain compiler issues.
(will_dump_p, will_bootstrap_p, will_dump_with_pdumper_p)
(dumped_with_pdumper_p): Adjust accordingly.
* src/pdumper.c (VM_SUPPORTED): Define to 0 when !USE_LSB_TAG.
It is better to read dump files into the heap by hand than to be
supplied with an address that is not representable.
(_dump_object_start_pseudovector): Rename to
dump_object_start_pseudovector, to avoid encroaching on reserved
names.
(START_DUMP_PVEC): Adjust correspondingly.
(dump_mmap_contiguous_vm): Preserve errno around failure
cleanup.
(dump_bitset_bit_set_p): Work around certain compiler issues.
(pdumper_load) [!USE_LSB_TAG]: Reject dump file allocations
that are not representable as Lisp_Objects.
Tested on i386-unknown-solaris2.10, sparc-sun-solaris2.10.
Diffstat (limited to 'src/pdumper.c')
| -rw-r--r-- | src/pdumper.c | 141 |
1 files changed, 83 insertions, 58 deletions
diff --git a/src/pdumper.c b/src/pdumper.c index 342c37b5e62..8e10e561bcf 100644 --- a/src/pdumper.c +++ b/src/pdumper.c | |||
| @@ -77,7 +77,9 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 77 | #define VM_POSIX 1 | 77 | #define VM_POSIX 1 |
| 78 | #define VM_MS_WINDOWS 2 | 78 | #define VM_MS_WINDOWS 2 |
| 79 | 79 | ||
| 80 | #if defined (HAVE_MMAP) && defined (MAP_FIXED) | 80 | #if !USE_LSB_TAG |
| 81 | # define VM_SUPPORTED 0 | ||
| 82 | #elif defined (HAVE_MMAP) && defined (MAP_FIXED) | ||
| 81 | # define VM_SUPPORTED VM_POSIX | 83 | # define VM_SUPPORTED VM_POSIX |
| 82 | # if !defined (MAP_POPULATE) && defined (MAP_PREFAULT_READ) | 84 | # if !defined (MAP_POPULATE) && defined (MAP_PREFAULT_READ) |
| 83 | # define MAP_POPULATE MAP_PREFAULT_READ | 85 | # define MAP_POPULATE MAP_PREFAULT_READ |
| @@ -1964,9 +1966,9 @@ dump_field_emacs_ptr (struct dump_context *ctx, | |||
| 1964 | } | 1966 | } |
| 1965 | 1967 | ||
| 1966 | static void | 1968 | static void |
| 1967 | _dump_object_start_pseudovector (struct dump_context *ctx, | 1969 | dump_object_start_pseudovector (struct dump_context *ctx, |
| 1968 | union vectorlike_header *out_hdr, | 1970 | union vectorlike_header *out_hdr, |
| 1969 | const union vectorlike_header *in_hdr) | 1971 | const union vectorlike_header *in_hdr) |
| 1970 | { | 1972 | { |
| 1971 | eassert (in_hdr->size & PSEUDOVECTOR_FLAG); | 1973 | eassert (in_hdr->size & PSEUDOVECTOR_FLAG); |
| 1972 | ptrdiff_t vec_size = vectorlike_nbytes (in_hdr); | 1974 | ptrdiff_t vec_size = vectorlike_nbytes (in_hdr); |
| @@ -1976,9 +1978,9 @@ _dump_object_start_pseudovector (struct dump_context *ctx, | |||
| 1976 | 1978 | ||
| 1977 | /* Need a macro for alloca. */ | 1979 | /* Need a macro for alloca. */ |
| 1978 | #define START_DUMP_PVEC(ctx, hdr, type, out) \ | 1980 | #define START_DUMP_PVEC(ctx, hdr, type, out) \ |
| 1979 | const union vectorlike_header *_in_hdr = (hdr); \ | 1981 | const union vectorlike_header *in_hdr = (hdr); \ |
| 1980 | type *out = alloca (vectorlike_nbytes (_in_hdr)); \ | 1982 | type *out = alloca (vectorlike_nbytes (in_hdr)); \ |
| 1981 | _dump_object_start_pseudovector (ctx, &out->header, _in_hdr) | 1983 | dump_object_start_pseudovector (ctx, &out->header, in_hdr) |
| 1982 | 1984 | ||
| 1983 | static dump_off | 1985 | static dump_off |
| 1984 | finish_dump_pvec (struct dump_context *ctx, | 1986 | finish_dump_pvec (struct dump_context *ctx, |
| @@ -3994,14 +3996,14 @@ dump_do_fixup (struct dump_context *ctx, | |||
| 3994 | Lisp_Object fixup, | 3996 | Lisp_Object fixup, |
| 3995 | Lisp_Object prev_fixup) | 3997 | Lisp_Object prev_fixup) |
| 3996 | { | 3998 | { |
| 3997 | enum dump_fixup_type type = | 3999 | enum dump_fixup_type type |
| 3998 | (enum dump_fixup_type) XFIXNUM (dump_pop (&fixup)); | 4000 | = (enum dump_fixup_type) XFIXNUM (dump_pop (&fixup)); |
| 3999 | dump_off dump_fixup_offset = dump_off_from_lisp (dump_pop (&fixup)); | 4001 | dump_off dump_fixup_offset = dump_off_from_lisp (dump_pop (&fixup)); |
| 4000 | #ifdef ENABLE_CHECKING | 4002 | #ifdef ENABLE_CHECKING |
| 4001 | if (!NILP (prev_fixup)) | 4003 | if (!NILP (prev_fixup)) |
| 4002 | { | 4004 | { |
| 4003 | dump_off prev_dump_fixup_offset = | 4005 | dump_off prev_dump_fixup_offset |
| 4004 | dump_off_from_lisp (XCAR (XCDR (prev_fixup))); | 4006 | = dump_off_from_lisp (XCAR (XCDR (prev_fixup))); |
| 4005 | eassert (dump_fixup_offset - prev_dump_fixup_offset | 4007 | eassert (dump_fixup_offset - prev_dump_fixup_offset |
| 4006 | >= sizeof (void *)); | 4008 | >= sizeof (void *)); |
| 4007 | } | 4009 | } |
| @@ -4618,23 +4620,8 @@ dump_anonymous_allocate_posix (void *base, | |||
| 4618 | } | 4620 | } |
| 4619 | #endif | 4621 | #endif |
| 4620 | 4622 | ||
| 4621 | /* Perform anonymous memory allocation. */ | 4623 | /* Undo the effect of `dump_reserve_address_space'. */ |
| 4622 | static void * | ||
| 4623 | dump_anonymous_allocate (void *base, | ||
| 4624 | const size_t size, | ||
| 4625 | enum dump_memory_protection protection) | ||
| 4626 | { | ||
| 4627 | #if VM_SUPPORTED == VM_POSIX | ||
| 4628 | return dump_anonymous_allocate_posix (base, size, protection); | ||
| 4629 | #elif VM_SUPPORTED == VM_MS_WINDOWS | ||
| 4630 | return dump_anonymous_allocate_w32 (base, size, protection); | ||
| 4631 | #else | ||
| 4632 | errno = ENOSYS; | ||
| 4633 | return NULL; | ||
| 4634 | #endif | ||
| 4635 | } | ||
| 4636 | 4624 | ||
| 4637 | /* Undo the effect of dump_reserve_address_space(). */ | ||
| 4638 | static void | 4625 | static void |
| 4639 | dump_anonymous_release (void *addr, size_t size) | 4626 | dump_anonymous_release (void *addr, size_t size) |
| 4640 | { | 4627 | { |
| @@ -4653,6 +4640,26 @@ dump_anonymous_release (void *addr, size_t size) | |||
| 4653 | #endif | 4640 | #endif |
| 4654 | } | 4641 | } |
| 4655 | 4642 | ||
| 4643 | /* Perform anonymous memory allocation. */ | ||
| 4644 | static void * | ||
| 4645 | dump_anonymous_allocate (void *base, | ||
| 4646 | const size_t size, | ||
| 4647 | enum dump_memory_protection protection) | ||
| 4648 | { | ||
| 4649 | void *val; | ||
| 4650 | |||
| 4651 | #if VM_SUPPORTED == VM_POSIX | ||
| 4652 | val = dump_anonymous_allocate_posix (base, size, protection); | ||
| 4653 | #elif VM_SUPPORTED == VM_MS_WINDOWS | ||
| 4654 | val = dump_anonymous_allocate_w32 (base, size, protection); | ||
| 4655 | #else | ||
| 4656 | errno = ENOSYS; | ||
| 4657 | val = NULL; | ||
| 4658 | #endif | ||
| 4659 | |||
| 4660 | return val; | ||
| 4661 | } | ||
| 4662 | |||
| 4656 | #if VM_SUPPORTED == VM_MS_WINDOWS | 4663 | #if VM_SUPPORTED == VM_MS_WINDOWS |
| 4657 | static void * | 4664 | static void * |
| 4658 | dump_map_file_w32 (void *base, int fd, off_t offset, size_t size, | 4665 | dump_map_file_w32 (void *base, int fd, off_t offset, size_t size, |
| @@ -4824,20 +4831,20 @@ static void | |||
| 4824 | dump_discard_mem (void *mem, size_t size) | 4831 | dump_discard_mem (void *mem, size_t size) |
| 4825 | { | 4832 | { |
| 4826 | #if VM_SUPPORTED == VM_MS_WINDOWS | 4833 | #if VM_SUPPORTED == VM_MS_WINDOWS |
| 4827 | /* Discard COWed pages. */ | 4834 | /* Discard COWed pages. */ |
| 4828 | (void) VirtualFree (mem, size, MEM_DECOMMIT); | 4835 | (void) VirtualFree (mem, size, MEM_DECOMMIT); |
| 4829 | /* Release the commit charge for the mapping. */ | 4836 | /* Release the commit charge for the mapping. */ |
| 4830 | DWORD old_prot; | 4837 | DWORD old_prot; |
| 4831 | (void) VirtualProtect (mem, size, PAGE_NOACCESS, &old_prot); | 4838 | (void) VirtualProtect (mem, size, PAGE_NOACCESS, &old_prot); |
| 4832 | #elif VM_SUPPORTED == VM_POSIX | 4839 | #elif VM_SUPPORTED == VM_POSIX |
| 4833 | # ifdef HAVE_POSIX_MADVISE | 4840 | # ifdef HAVE_POSIX_MADVISE |
| 4834 | /* Discard COWed pages. */ | 4841 | /* Discard COWed pages. */ |
| 4835 | (void) posix_madvise (mem, size, POSIX_MADV_DONTNEED); | 4842 | (void) posix_madvise (mem, size, POSIX_MADV_DONTNEED); |
| 4836 | # elif defined HAVE_MADVISE | 4843 | # elif defined HAVE_MADVISE |
| 4837 | (void) madvise (mem, size, MADV_DONTNEED); | 4844 | (void) madvise (mem, size, MADV_DONTNEED); |
| 4838 | #endif | 4845 | #endif |
| 4839 | /* Release the commit charge for the mapping. */ | 4846 | /* Release the commit charge for the mapping. */ |
| 4840 | (void) mprotect (mem, size, PROT_NONE); | 4847 | (void) mprotect (mem, size, PROT_NONE); |
| 4841 | #endif | 4848 | #endif |
| 4842 | } | 4849 | } |
| 4843 | 4850 | ||
| @@ -4959,21 +4966,23 @@ dump_mmap_release_vm (struct dump_memory_map *map) | |||
| 4959 | static bool | 4966 | static bool |
| 4960 | needs_mmap_retry_p (void) | 4967 | needs_mmap_retry_p (void) |
| 4961 | { | 4968 | { |
| 4962 | #if defined CYGWIN || VM_SUPPORTED == VM_MS_WINDOWS || defined _AIX | 4969 | #if defined CYGWIN || VM_SUPPORTED == VM_MS_WINDOWS \ |
| 4970 | || defined _AIX | ||
| 4963 | return true; | 4971 | return true; |
| 4964 | #else | 4972 | #else /* !CYGWIN && VM_SUPPORTED != VM_MS_WINDOWS && !_AIX */ |
| 4965 | return false; | 4973 | return false; |
| 4966 | #endif | 4974 | #endif /* !CYGWIN && VM_SUPPORTED != VM_MS_WINDOWS && !_AIX */ |
| 4967 | } | 4975 | } |
| 4968 | 4976 | ||
| 4969 | static bool | 4977 | static bool |
| 4970 | dump_mmap_contiguous_vm (struct dump_memory_map *maps, int nr_maps, | 4978 | dump_mmap_contiguous_vm (struct dump_memory_map *maps, int nr_maps, |
| 4971 | size_t total_size) | 4979 | size_t total_size) |
| 4972 | { | 4980 | { |
| 4981 | int save_errno; | ||
| 4973 | bool ret = false; | 4982 | bool ret = false; |
| 4974 | void *resv = NULL; | 4983 | void *resv = NULL; |
| 4975 | bool retry = false; | 4984 | bool retry = false; |
| 4976 | const bool need_retry = needs_mmap_retry_p (); | 4985 | bool need_retry = needs_mmap_retry_p (); |
| 4977 | 4986 | ||
| 4978 | do | 4987 | do |
| 4979 | { | 4988 | { |
| @@ -4986,11 +4995,10 @@ dump_mmap_contiguous_vm (struct dump_memory_map *maps, int nr_maps, | |||
| 4986 | } | 4995 | } |
| 4987 | 4996 | ||
| 4988 | eassert (resv == NULL); | 4997 | eassert (resv == NULL); |
| 4989 | resv = dump_anonymous_allocate (NULL, | 4998 | resv = dump_anonymous_allocate (NULL, total_size, |
| 4990 | total_size, | ||
| 4991 | DUMP_MEMORY_ACCESS_NONE); | 4999 | DUMP_MEMORY_ACCESS_NONE); |
| 4992 | if (!resv) | 5000 | if (!resv) |
| 4993 | goto out; | 5001 | goto out; |
| 4994 | 5002 | ||
| 4995 | char *mem = resv; | 5003 | char *mem = resv; |
| 4996 | 5004 | ||
| @@ -5039,6 +5047,7 @@ dump_mmap_contiguous_vm (struct dump_memory_map *maps, int nr_maps, | |||
| 5039 | ret = true; | 5047 | ret = true; |
| 5040 | resv = NULL; | 5048 | resv = NULL; |
| 5041 | out: | 5049 | out: |
| 5050 | save_errno = errno; | ||
| 5042 | if (resv) | 5051 | if (resv) |
| 5043 | dump_anonymous_release (resv, total_size); | 5052 | dump_anonymous_release (resv, total_size); |
| 5044 | if (!ret) | 5053 | if (!ret) |
| @@ -5051,6 +5060,7 @@ dump_mmap_contiguous_vm (struct dump_memory_map *maps, int nr_maps, | |||
| 5051 | dump_mmap_release (&maps[i]); | 5060 | dump_mmap_release (&maps[i]); |
| 5052 | } | 5061 | } |
| 5053 | } | 5062 | } |
| 5063 | errno = save_errno; | ||
| 5054 | return ret; | 5064 | return ret; |
| 5055 | } | 5065 | } |
| 5056 | 5066 | ||
| @@ -5058,8 +5068,8 @@ dump_mmap_contiguous_vm (struct dump_memory_map *maps, int nr_maps, | |||
| 5058 | 5068 | ||
| 5059 | Each dump_memory_map structure describes how to fill the | 5069 | Each dump_memory_map structure describes how to fill the |
| 5060 | corresponding range of memory. On input, all members except MAPPING | 5070 | corresponding range of memory. On input, all members except MAPPING |
| 5061 | are valid. On output, MAPPING contains the location of the given | 5071 | are valid. On output, MAPPING contains the location of the given |
| 5062 | chunk of memory. The MAPPING for MAPS[N] is MAPS[N-1].mapping + | 5072 | chunk of memory. The MAPPING for MAPS[N] is MAPS[N-1].mapping + |
| 5063 | MAPS[N-1].size. | 5073 | MAPS[N-1].size. |
| 5064 | 5074 | ||
| 5065 | Each mapping SIZE must be a multiple of the system page size except | 5075 | Each mapping SIZE must be a multiple of the system page size except |
| @@ -5085,8 +5095,10 @@ dump_mmap_contiguous (struct dump_memory_map *maps, int nr_maps) | |||
| 5085 | total_size += maps[i].spec.size; | 5095 | total_size += maps[i].spec.size; |
| 5086 | } | 5096 | } |
| 5087 | 5097 | ||
| 5088 | return (VM_SUPPORTED ? dump_mmap_contiguous_vm : dump_mmap_contiguous_heap) | 5098 | if (VM_SUPPORTED) |
| 5089 | (maps, nr_maps, total_size); | 5099 | return dump_mmap_contiguous_vm (maps, nr_maps, total_size); |
| 5100 | else | ||
| 5101 | return dump_mmap_contiguous_heap (maps, nr_maps, total_size); | ||
| 5090 | } | 5102 | } |
| 5091 | 5103 | ||
| 5092 | typedef uint_fast32_t dump_bitset_word; | 5104 | typedef uint_fast32_t dump_bitset_word; |
| @@ -5129,7 +5141,7 @@ dump_bitset_bit_set_p (const struct dump_bitset *bitset, | |||
| 5129 | { | 5141 | { |
| 5130 | dump_bitset_word bit = 1; | 5142 | dump_bitset_word bit = 1; |
| 5131 | bit <<= bit_number % DUMP_BITSET_WORD_WIDTH; | 5143 | bit <<= bit_number % DUMP_BITSET_WORD_WIDTH; |
| 5132 | return *dump_bitset__bit_slot (bitset, bit_number) & bit; | 5144 | return (*dump_bitset__bit_slot (bitset, bit_number) & bit) != 0; |
| 5133 | } | 5145 | } |
| 5134 | 5146 | ||
| 5135 | static void | 5147 | static void |
| @@ -5548,8 +5560,8 @@ dump_do_dump_relocation (const uintptr_t dump_base, | |||
| 5548 | struct bignum_reload_info reload_info; | 5560 | struct bignum_reload_info reload_info; |
| 5549 | static_assert (sizeof (reload_info) <= sizeof (*bignum_val (bignum))); | 5561 | static_assert (sizeof (reload_info) <= sizeof (*bignum_val (bignum))); |
| 5550 | memcpy (&reload_info, bignum_val (bignum), sizeof (reload_info)); | 5562 | memcpy (&reload_info, bignum_val (bignum), sizeof (reload_info)); |
| 5551 | const mp_limb_t *limbs = | 5563 | const mp_limb_t *limbs = dump_ptr (dump_base, |
| 5552 | dump_ptr (dump_base, reload_info.data_location); | 5564 | reload_info.data_location); |
| 5553 | mpz_roinit_n (bignum->value, limbs, reload_info.nlimbs); | 5565 | mpz_roinit_n (bignum->value, limbs, reload_info.nlimbs); |
| 5554 | break; | 5566 | break; |
| 5555 | } | 5567 | } |
| @@ -5790,15 +5802,29 @@ pdumper_load (const char *dump_filename, char *argv0) | |||
| 5790 | goto out; | 5802 | goto out; |
| 5791 | 5803 | ||
| 5792 | err = PDUMPER_LOAD_ERROR; | 5804 | err = PDUMPER_LOAD_ERROR; |
| 5793 | mark_bits_needed = | 5805 | dump_base = (uintptr_t) sections[DS_HOT].mapping; |
| 5794 | divide_round_up (header->discardable_start, DUMP_ALIGNMENT); | 5806 | |
| 5807 | #if !USE_LSB_TAG | ||
| 5808 | /* The dump may have been mapped at a location that does not admit of | ||
| 5809 | representation as Lisp_Objects. Abort in this case. */ | ||
| 5810 | if ((dump_base + dump_size) & ~VALMASK) | ||
| 5811 | { | ||
| 5812 | fprintf (stderr, | ||
| 5813 | "Failed to load dump file: 0x%p+0x%p & 0x%p != 0\n", | ||
| 5814 | (void *) dump_base, (void *) dump_size, | ||
| 5815 | (void *) (uintptr_t) VALMASK); | ||
| 5816 | goto out; | ||
| 5817 | } | ||
| 5818 | #endif /* !USE_LSB_TAG */ | ||
| 5819 | |||
| 5820 | mark_bits_needed | ||
| 5821 | = divide_round_up (header->discardable_start, DUMP_ALIGNMENT); | ||
| 5795 | if (!dump_bitsets_init (mark_bits, mark_bits_needed)) | 5822 | if (!dump_bitsets_init (mark_bits, mark_bits_needed)) |
| 5796 | goto out; | 5823 | goto out; |
| 5797 | 5824 | ||
| 5798 | /* Point of no return. */ | 5825 | /* Point of no return. */ |
| 5799 | err = PDUMPER_LOAD_SUCCESS; | 5826 | err = PDUMPER_LOAD_SUCCESS; |
| 5800 | dump_base = (uintptr_t) sections[DS_HOT].mapping; | 5827 | gflags.dumped_with_pdumper = true; |
| 5801 | gflags.dumped_with_pdumper_ = true; | ||
| 5802 | dump_private.header = *header; | 5828 | dump_private.header = *header; |
| 5803 | dump_private.mark_bits = mark_bits[0]; | 5829 | dump_private.mark_bits = mark_bits[0]; |
| 5804 | dump_private.last_mark_bits = mark_bits[1]; | 5830 | dump_private.last_mark_bits = mark_bits[1]; |
| @@ -5815,8 +5841,8 @@ pdumper_load (const char *dump_filename, char *argv0) | |||
| 5815 | Lisp_Object hashes = zero_vector; | 5841 | Lisp_Object hashes = zero_vector; |
| 5816 | if (header->hash_list) | 5842 | if (header->hash_list) |
| 5817 | { | 5843 | { |
| 5818 | struct Lisp_Vector *hash_tables = | 5844 | struct Lisp_Vector *hash_tables |
| 5819 | (struct Lisp_Vector *) (dump_base + header->hash_list); | 5845 | = (struct Lisp_Vector *) (dump_base + header->hash_list); |
| 5820 | hashes = make_lisp_ptr (hash_tables, Lisp_Vectorlike); | 5846 | hashes = make_lisp_ptr (hash_tables, Lisp_Vectorlike); |
| 5821 | } | 5847 | } |
| 5822 | 5848 | ||
| @@ -5852,7 +5878,6 @@ pdumper_load (const char *dump_filename, char *argv0) | |||
| 5852 | dump_mmap_release (§ions[i]); | 5878 | dump_mmap_release (§ions[i]); |
| 5853 | if (dump_fd >= 0) | 5879 | if (dump_fd >= 0) |
| 5854 | emacs_close (dump_fd); | 5880 | emacs_close (dump_fd); |
| 5855 | |||
| 5856 | return err; | 5881 | return err; |
| 5857 | } | 5882 | } |
| 5858 | 5883 | ||