134134 stream :: stream (),
135135 offset :: non_neg_integer (),
136136 branches :: [{non_neg_integer (), non_neg_integer (), non_neg_integer ()}],
137+ jump_table_start :: non_neg_integer (),
137138 available_regs :: [armv6m_register ()],
138139 used_regs :: [armv6m_register ()],
139140 labels :: [{integer () | reference (), integer ()}],
@@ -247,6 +248,7 @@ new(Variant, StreamModule, Stream) ->
247248 stream_module = StreamModule ,
248249 stream = Stream ,
249250 branches = [],
251+ jump_table_start = 0 ,
250252 offset = StreamModule :offset (Stream ),
251253 available_regs = ? AVAILABLE_REGS ,
252254 used_regs = [],
@@ -380,13 +382,14 @@ assert_all_native_free(#state{
380382% % @return Updated backend state
381383% %-----------------------------------------------------------------------------
382384-spec jump_table (state (), pos_integer ()) -> state ().
383- jump_table (State , LabelsCount ) ->
384- jump_table0 (State , 0 , LabelsCount ).
385+ jump_table (# state {stream_module = StreamModule , stream = Stream0 } = State , LabelsCount ) ->
386+ JumpTableStart = StreamModule :offset (Stream0 ),
387+ jump_table0 (State # state {jump_table_start = JumpTableStart }, 0 , LabelsCount ).
385388
386389jump_table0 (State , N , LabelsCount ) when N > LabelsCount ->
387390 State ;
388391jump_table0 (
389- # state {stream_module = StreamModule , stream = Stream0 , branches = Branches } = State ,
392+ # state {stream_module = StreamModule , stream = Stream0 } = State ,
390393 N ,
391394 LabelsCount
392395) ->
@@ -399,15 +402,7 @@ jump_table0(
399402 JumpEntry = <<I1 /binary , I2 /binary , I3 /binary , I4 /binary , 16#FFFFFFFF :32 >>,
400403 Stream1 = StreamModule :append (Stream0 , JumpEntry ),
401404
402- % Add relocation for the data entry so update_branches/2 can patch the jump target
403- DataOffset = StreamModule :offset (Stream1 ) - 4 ,
404- % Calculate the offset of the add instruction (3rd instruction, at offset 4 from entry start)
405- EntryStartOffset = StreamModule :offset (Stream1 ) - 12 ,
406- AddInstrOffset = EntryStartOffset + 4 ,
407- DataReloc = {N , DataOffset , {jump_table_data , AddInstrOffset }},
408- UpdatedState = State # state {stream = Stream1 , branches = [DataReloc | Branches ]},
409-
410- jump_table0 (UpdatedState , N + 1 , LabelsCount ).
405+ jump_table0 (State # state {stream = Stream1 }, N + 1 , LabelsCount ).
411406
412407% %-----------------------------------------------------------------------------
413408% % @doc Rewrite stream to update all branches for labels.
@@ -500,13 +495,7 @@ update_branches(
500495 I4 = <<RelativeOffset :32 /little >>,
501496 <<I1 /binary , I2 /binary , I3 /binary , I4 /binary >>
502497 end
503- end ;
504- {jump_table_data , AddInstrOffset } ->
505- % Calculate offset from 'add pc, pc, r3' instruction + 4 to target label
506- % PC when add instruction executes
507- AddPC = AddInstrOffset + 4 ,
508- RelativeOffset = LabelOffset - AddPC ,
509- <<RelativeOffset :32 /little >>
498+ end
510499 end ,
511500 Stream1 = StreamModule :replace (Stream0 , Offset , NewInstr ),
512501 update_branches (State # state {stream = Stream1 , branches = BranchesT }).
@@ -3288,5 +3277,34 @@ add_label(#state{stream_module = StreamModule, stream = Stream0} = State0, Label
32883277% % @return Updated backend state
32893278% %-----------------------------------------------------------------------------
32903279- spec add_label (state (), integer () | reference (), integer ()) -> state ().
3280+ add_label (
3281+ # state {
3282+ stream_module = StreamModule ,
3283+ stream = Stream0 ,
3284+ jump_table_start = JumpTableStart ,
3285+ labels = Labels
3286+ } = State ,
3287+ Label ,
3288+ LabelOffset
3289+ ) when is_integer (Label ) ->
3290+ % Patch the jump table entry immediately
3291+ % Each jump table entry is 12 bytes:
3292+ % - ldr r3, [pc, 4] (2 bytes) at offset 0
3293+ % - push {...} (2 bytes) at offset 2
3294+ % - add pc, r3 (2 bytes) at offset 4
3295+ % - nop (2 bytes) at offset 6
3296+ % - data (4 bytes) at offset 8
3297+ JumpTableEntryStart = JumpTableStart + Label * 12 ,
3298+ DataOffset = JumpTableEntryStart + 8 ,
3299+ AddInstrOffset = JumpTableEntryStart + 4 ,
3300+
3301+ % Calculate offset from 'add pc, pc, r3' instruction + 4 to target label
3302+ % PC when add instruction executes
3303+ AddPC = AddInstrOffset + 4 ,
3304+ RelativeOffset = LabelOffset - AddPC ,
3305+ DataBytes = <<RelativeOffset :32 /little >>,
3306+
3307+ Stream1 = StreamModule :replace (Stream0 , DataOffset , DataBytes ),
3308+ State # state {stream = Stream1 , labels = [{Label , LabelOffset } | Labels ]};
32913309add_label (# state {labels = Labels } = State , Label , Offset ) ->
32923310 State # state {labels = [{Label , Offset } | Labels ]}.
0 commit comments