133133 stream :: stream (),
134134 offset :: non_neg_integer (),
135135 branches :: [{non_neg_integer (), non_neg_integer (), non_neg_integer ()}],
136+ jump_table_start :: non_neg_integer (),
136137 available_regs :: [armv6m_register ()],
137138 used_regs :: [armv6m_register ()],
138139 labels :: [{integer () | reference (), integer ()}],
@@ -246,6 +247,7 @@ new(Variant, StreamModule, Stream) ->
246247 stream_module = StreamModule ,
247248 stream = Stream ,
248249 branches = [],
250+ jump_table_start = 0 ,
249251 offset = StreamModule :offset (Stream ),
250252 available_regs = ? AVAILABLE_REGS ,
251253 used_regs = [],
@@ -379,13 +381,14 @@ assert_all_native_free(#state{
379381% % @return Updated backend state
380382% %-----------------------------------------------------------------------------
381383-spec jump_table (state (), pos_integer ()) -> state ().
382- jump_table (State , LabelsCount ) ->
383- jump_table0 (State , 0 , LabelsCount ).
384+ jump_table (# state {stream_module = StreamModule , stream = Stream0 } = State , LabelsCount ) ->
385+ JumpTableStart = StreamModule :offset (Stream0 ),
386+ jump_table0 (State # state {jump_table_start = JumpTableStart }, 0 , LabelsCount ).
384387
385388jump_table0 (State , N , LabelsCount ) when N > LabelsCount ->
386389 State ;
387390jump_table0 (
388- # state {stream_module = StreamModule , stream = Stream0 , branches = Branches } = State ,
391+ # state {stream_module = StreamModule , stream = Stream0 } = State ,
389392 N ,
390393 LabelsCount
391394) ->
@@ -398,15 +401,7 @@ jump_table0(
398401 JumpEntry = <<I1 /binary , I2 /binary , I3 /binary , I4 /binary , 16#FFFFFFFF :32 >>,
399402 Stream1 = StreamModule :append (Stream0 , JumpEntry ),
400403
401- % Add relocation for the data entry so update_branches/2 can patch the jump target
402- DataOffset = StreamModule :offset (Stream1 ) - 4 ,
403- % Calculate the offset of the add instruction (3rd instruction, at offset 4 from entry start)
404- EntryStartOffset = StreamModule :offset (Stream1 ) - 12 ,
405- AddInstrOffset = EntryStartOffset + 4 ,
406- DataReloc = {N , DataOffset , {jump_table_data , AddInstrOffset }},
407- UpdatedState = State # state {stream = Stream1 , branches = [DataReloc | Branches ]},
408-
409- jump_table0 (UpdatedState , N + 1 , LabelsCount ).
404+ jump_table0 (State # state {stream = Stream1 }, N + 1 , LabelsCount ).
410405
411406% %-----------------------------------------------------------------------------
412407% % @doc Rewrite stream to update all branches for labels.
@@ -499,13 +494,7 @@ update_branches(
499494 I4 = <<RelativeOffset :32 /little >>,
500495 <<I1 /binary , I2 /binary , I3 /binary , I4 /binary >>
501496 end
502- end ;
503- {jump_table_data , AddInstrOffset } ->
504- % Calculate offset from 'add pc, pc, r3' instruction + 4 to target label
505- % PC when add instruction executes
506- AddPC = AddInstrOffset + 4 ,
507- RelativeOffset = LabelOffset - AddPC ,
508- <<RelativeOffset :32 /little >>
497+ end
509498 end ,
510499 Stream1 = StreamModule :replace (Stream0 , Offset , NewInstr ),
511500 update_branches (State # state {stream = Stream1 , branches = BranchesT }).
@@ -3143,5 +3132,34 @@ add_label(#state{stream_module = StreamModule, stream = Stream0} = State0, Label
31433132% % @return Updated backend state
31443133% %-----------------------------------------------------------------------------
31453134- spec add_label (state (), integer () | reference (), integer ()) -> state ().
3135+ add_label (
3136+ # state {
3137+ stream_module = StreamModule ,
3138+ stream = Stream0 ,
3139+ jump_table_start = JumpTableStart ,
3140+ labels = Labels
3141+ } = State ,
3142+ Label ,
3143+ LabelOffset
3144+ ) when is_integer (Label ) ->
3145+ % Patch the jump table entry immediately
3146+ % Each jump table entry is 12 bytes:
3147+ % - ldr r3, [pc, 4] (2 bytes) at offset 0
3148+ % - push {...} (2 bytes) at offset 2
3149+ % - add pc, r3 (2 bytes) at offset 4
3150+ % - nop (2 bytes) at offset 6
3151+ % - data (4 bytes) at offset 8
3152+ JumpTableEntryStart = JumpTableStart + Label * 12 ,
3153+ DataOffset = JumpTableEntryStart + 8 ,
3154+ AddInstrOffset = JumpTableEntryStart + 4 ,
3155+
3156+ % Calculate offset from 'add pc, pc, r3' instruction + 4 to target label
3157+ % PC when add instruction executes
3158+ AddPC = AddInstrOffset + 4 ,
3159+ RelativeOffset = LabelOffset - AddPC ,
3160+ DataBytes = <<RelativeOffset :32 /little >>,
3161+
3162+ Stream1 = StreamModule :replace (Stream0 , DataOffset , DataBytes ),
3163+ State # state {stream = Stream1 , labels = [{Label , LabelOffset } | Labels ]};
31463164add_label (# state {labels = Labels } = State , Label , Offset ) ->
31473165 State # state {labels = [{Label , Offset } | Labels ]}.
0 commit comments