Hello and happy new year,
I am attempting to implement relaxations on my out-of-tree target, and I'm encountering the "attempt to move .org backwards" error. I would appreciate any help diagnosing my mistake. My work is based on the 2.25.1 (git hash 2bd25930...)
While tracing through the relaxation process of a small testcase, it seems like the stretch term is being inappropriately added to the offset of an rs_org fragment (near the top of the loop in relax_segment, write.c, line 2496). That violates my understanding of the .org: why would changing the size of earlier fragments affect the absolute address of a subsequent .org fragment? And why is it bad to move a .org fragment backwards, yet acceptable to move a .org fragment forward?
Below is everything I know about how my setup produces the error.
My testcase, below, features a machine-dependent relaxation on the pc-relative branch 'beq'. That branch defaults to an 8-byte "long-form" though can be relaxed to a 4-byte "short-form" when the branch displacement is small.
# begin testcase
label1:
beq r3.3, r5.1, label2, 0 # machine-dependent relaxation
.org 0x1000
label2:
#end testcase
I implemented md_estimate_size_before_relax, md_relax_frag, and md_convert_frag. This is the sequence of events:
(1) md_estimate_size_before_relax returns '8' to indicate an 8-byte instruction.
(2) md_relax_frag is called thrice on this fragment. First call: the frag containing 'label2' had not been visited yet, and so md_relax_frag thinks label2 is at offset 8 (initially incorrect). Since the displacement is small, md_relax_frag opts for a short-form instruction and returns -4 (==4bytes - 8bytes).
(3) Second call to md_relax_frag: the frag containing label2 has been visited, and so md_relax_frag thinks label2 is at offset 0x1000 (correct). The branch displacement is large, so md_relax_frag opts for a long-form instruction and returns +4 (==8bytes - 4bytes).
(4) md_relax_frag is called a third time. Md_relax_frag now estimates that label2 is at offset 0x1004. This offset is incorrect, perhaps indicating that the stretch term was inappropriatetly applied to an rs_org frag. The branch displacement is still large, and again md_relax_frag opts for a long-form instruction and returns 0 (==8bytes - 8bytes).
(5--8) Repeats steps [1--4] exactly. (9--12) Repeats steps [1--4], except step 11 triggers the "attempt to move .org backwards" error.
(13) md_convert_frag is called for the first time. It leaves the long-form instruction unchanged, sets fragP->fr_fix += 8 and fragP->fr_var = 0.
Thank you,
Nick Johnson
D. E. Shaw Research