about summary refs log blame commit diff stats
path: root/apps/survey.subx
blob: aabd1cfa94481885223eeb1ccd8888d22b5a867d (plain) (tree)
1
2
3
4
5
6
7
8
9



                                                                          
                                                                         
 
           
                                                                                     
 























                                                                                 



                                                                              






                                                                                                                                                 
                                   

                       
                                                                                                                                                                       


                               
                                                                                                                                                                  





                                           
                                                                                                                                                                  
 

                                                  
                                                                                                                                                                       

                                                                  
                                                                                                                                                                    



                                               
                                                                                                                                                                     


                                        
                                                                                                                                                                  
                    
                               


                                         
                                                                                                                                                                                      


                               
                            
                   




                           
                                                                                                                                                                  






                                                                                                                                                                             
                                                                                                                                                                     
                        
                           
          
                                

                         




                                                                            
                                                             
 
                                                                                     
                

                                                     
                                                         
                                                               




                                              
              

                                                                                                                                                                       
                      




                                                                                                                                                                         


                              

                                                                                                                                                                       
            
                                                                                                                                                                                     


                                                                                                                                                                        
                         
             
                          

                                                                                                                                                                       
            
                                                                                                                                                                                     
              
                                                                                                                                                                        
            
                         
             
                          
                                                                                                                                                                       







                                                                        
                                                                                                                                                                     
                                 

                     
                      


                                   


                                   


                                                                                                                                                                     


                                                      
                                                                                                                                                                    



                                           
                                                                                                                                                                     





                            
                                                                                                                                                                     






                                
                                                                                                                                                                     
            






                                          
                                                                                                                                                                     
            

                       

                                                                                                                                                                     


                         
                                                                                                                                                                  







                                                         
                                                                                                                                                                     
                                 

                     
                      


                                   


                                   


                                                                                                                                                                     

                                                      
                                                                                                                                                                    



                                           
                                                                                                                                                                     





                            
                                                                                                                                                                     






                                
                                                                                                                                                                     
            







                                  
                                                                                                                                                                     

                                   
                  



                                   
                                                                                                                                                                     






                                 
                                                                                                                                                                     

                            
                  


                                    
                                                                                                                                                                     
            






                                                 
                                                                                                                                                                     
            

                                           


               


                                   
                                                                                                                                                                  






                                                   
                                                                                                                                                                     
            

                                         

               


                                     
                                                                                                                                                                  

                       
               


                                 
                                                                                                                                                                  
                                             
                      

                                     
                 

                            
                                                                                                                                                                     








                               
                                                                                                                                                                     






                                                                                                                                                                             
                                                                                                                                                                     






                                 
                                                                                                                                                                     








                                                                   
                                                                                                                                                                     
                                 

                     
                      


                                   

                                   
                         


                                                                                                                                                                     
                                               
                      
                                                                                                                                                                    
                            
                 
                                           
                         
                                                                                                                                                                     
                        
                      
                            


                            
                                                                                                                                                                     






                                
                                                                                                                                                                     


                                            



                                                                                                                                                                      


                               
                                                                                                                                                                  

                   
                                                                                                                                                                      


                         
                                                                                                                                                                  

                      
                                                                                                                                                                  
                         


                 
              

                                                                                                                                                                       

             


                                
              











                                             

                                                                                                                                                                       






                                        
                                                                                                                                                                  

                                                 


                                                   


                                
                                                                                                                                                                  





                                         
                                                                                                                                                                  

                                                  


                                                    


                                
                                                                                                                                                                  







                                                  
                                                                                                                                                                  






                                             
                                                                                                                                                                  






                                                 
                                                                                                                                                                  






                                                     
                                                                                                                                                                  






                                         
                                                                                                                                                                  






                                         
                                                                                                                                                                  






                                                                    
                                                                                                                                                                  
                 







                               
                                                                                                                                                                     






                                                                                                                                                                             
                                                                                                                                                                     






                                 
                                                                                                                                                                     

                                                                        

                                                          
                                                        


                                        
                                                                                                                                                                  
                                                                                 

                                                          
                                                                 


                                        
                                                                                                                                                                  
                                                                        

                                                          
                                                        


                                        
                                                                                                                                                                  
                                                                                 

                                                          
                                                                 


                                        
                                                                                                                                                                  
              

                                                                                                                                                                       

             


                                                              
                                   
         
                                      


                           
             
                                     

               


       
                                                                                                                                             








                           
                 
                                                
                                     
                                                               
                            
                             
                                                                 
                                                               
                                        

                                                                 
                                                                  
                                                                 
                                                  

                                                                
                                                           
                                                                               


                                                              
                     

                                           
                     
                                                              
                                                                
                                             
                                                                                             
                                



                                                                    
                                                 
                                                                                        
                                                

                                                                                          
                
                                                        

                                      

              

                                                                                                                                                                       
                      







                                                                                                                                                                 
                     
                                                                                                                                                                                                                   
                        
                                                                                                                                                                                                                   

                                   
                   

                        
                       
              
                              
                      


                                                                                                                                                                       
                           

                            

                                



                                                                                                                                                                     
                             
                    
                                                                                                                                                                  
                                 

                                                                                                                                                                        
                                                                







                                  
                                                                                                                                                                     

                                     
                  



                                   
                                                                                                                                                                     






                                 
                                                                                                                                                                     

                              
                  


                                    
                                                                                                                                                                     
            
                           




                                                    

                             
                                                                                                                                                                  
                                                        
                                 
                      
                           



                              
                                                                                                                                                                     
                                 

                     
                      


                                   


                                   


                                                                                                                                                                     

                                                   
                  



                                           
                                                                                                                                                                     





                            
                                                                                                                                                                     






                                 
                                                                                                                                                                     
                                                              
                                                                                                                                                                      
                                                          






                                                        
                                                                                                                                                                     

                                                    
                  



                                     
                                                                                                                                                                     





                            
                                                                                                                                                                     






                                 
                                                                                                                                                                     
            
                            


                                     

                                


                                                                                                                                                                  
                                                              
                              

                                                     
               

                                      


                                                                                                                                                                  
                                                              
                                     

                                                             
                       
               

                                


                                                                                                                                                                  
                                                           
                                                             
                                                                                                                                                                   
                                                                   
                                                                       
                   
                                

                                                                                                                                                                      
              
                                 
                      
                                                                                                                                                                  
                                                











                                                                                                                                                                                 
                                                                                
                   
                      
               
                                
               
                              
              
                               
                      
                                                                                                                                                                  
                                        
                                      
                                              
               

                             

                                                                                                                                                                  
                                                                    
                                                                                                                                                                      







                                                                        
                                                                                                                                                                     

                                 


                                   


                                   


                                                                                                                                                                     

                                                    
                  



                                     
                                                                                                                                                                     





                            
                                                                                                                                                                     






                                 
                                                                                                                                                                     
            

                                                      
                                                




                                              
                      


                                                                                                                                                                       
                                        

                               
                                                      
                                      
                                              
               

                             
                                                                                                                                                                  
                                        
                                       
                                              

                                


                                                                                                                                                                  
                                                          
                                                                       
                   
                                

                                                                                                                                                                      
              
                                 
                      


                                                                                                                                                                       
                                               
                                        
                                              

                                 


                                                                                                                                                                        
                                     

                                                                                                                                                                                 
                                                                                               
                   
                      
               
                                         
               
                              
              
                               
                      
                                                                                                                                                                  

                                                                                                                                                                                                
           
                                             
                            

                                                    
                   
               


                             


                                                                                                                                                                  
                                                         
                                        

                                                                                                                                                                          

                                

                                                                                                                                                                      
              
                                             
                      
                                                                                                                                                                  
                                   
                                         

                                                                                                                                                                        

                       
               
                                      
               



                               
                                                                                                                                                                  
                                        








                                                                                                                                                                                        

                      
               
                                            
               



                               
                                                                                                                                                                  

                                              
                              
                                                    
                   
               

                                         
                      
                                                                                                                                                                  
                             
                                                                                                                                                                                      
                          
                                                                                                                                                                                







                                              
                                                                                                                                                                     
                                 

                     
                      


                                   


                                   


                                                                                                                                                                     

                                                       
                  




                                                                                                                                                                                    
                                                                                                                                                                     





                            
                                                                                                                                                                     






                                
                                                                                                                                                                     
            
                                             
                                 
                                                                       

                                

                                                                                                                                                                      


                                 
                                                                                                                                                                  
                                                











                                                                                                                                                                                 
                                                                                
                                                                            

                      
               
                                
               



                               
                                                                                                                                                                  


                         





                 
              

                                                                                                                                                                       
             
 







                                                                              
                                                                                                                                                                  
                        

                                

                         



                     
                                  
                      
          
          
            

                                    





                                             

              

                                                                                                                                                                       
           





                                        


                                                                                                                                                                         


                              


                                                                                                                                                                         


                              
                                                                                                                                                                       







                                                  
                                                                                                                                                                  
                                                                 
                   
                                                 



                                     
                                                                                                                                                                  






                                                     
                                                                                                                                                                  






                                         
                                                                                                                                                                  






                                         
                                                                                                                                                                  






                                         
                                                                                                                                                                  
                                                           
                   

               
                                     


                                   
                                                                                                                                                                 







                               
                                                                                                                                                                     






                                                                                                                                                                             
                                                                                                                                                                     






                                 
                                                                                                                                                                     
            
                 
                                                                                 

                                               
                                                                 


                                        
                                                                                                                                                                  
                                                                       

                                               
                                                        


                                        
                                                                                                                                                                  
                                                                                 

                                               
                                                                 


                                        
                                                                                                                                                                  
                                                                        

                                               
                                                        


                                        
                                                                                                                                                                  
                                                                    

                                               
                                                    


                                        
                                                                                                                                                                  
                                                                               

                                               
                                                               

                                        
                      
                                                                                                                                                                  



                                                                          
                                                                                                                                                                 


                                    
                                                                                                                                                                  
              

                                                                                                                                                                       



                                                                                                                        
                                                      
                                              

                                                      
                  
                                
                                           

                                                                    
                                                                         

                                                  

                                          

                                                          
                                                                      


                                                                         

              

                                                                                                                                                                       
                      



















                                                                                                                                                                                                       
                                
                            
                                                                                                                                                                            
                                                                                
                                          
                                                                                                                                                                           
                                                            



                                                                                                                                                                            
                                                






                                                                                                                                                                                 
                                                                          
                   
                      
               
                                         
                                                                                                                                                                 
                              
              
                               
                      
                                                                                                                                                                  
                               
                             
                                                  
                                 







                               
                                                                                                                                                                     






                                                                                                                                                                             
                                                                                                                                                                     






                                 
                                                                                                                                                                     
            






                                                                                                                                                                             
                              
                            
                                                                                                                                                                            
                                                                          







                                     
                                                                                                                                                                     

                                     
                                                                                                                                                                    



                              
                                                                                                                                                                     






                                 
                                                                                                                                                                     
            

                                                                                                                                                                        







                                                           
                                                                                                                                                                     

                                    
                  



                              
                                                                                                                                                                     






                                 
                                                                                                                                                                     
            



                                                                                                    
                   
                                  
                                

                                                                                                                                                                     
              
                       
                      










                                                                                                                                                                             


                                                                         
               
                                     
                                                                                                                                                                 



                               
                                                                                                                                                                  
                               
                             
                                                 
                       
                         





                 
              

                                                                                                                                                                       


                       







                                
     



                                                                                 

                                                                              

              

                                                                                                                                                                       
           

                                                                                                                                                                         


                              


                                                                                                                                                                         


                                
                                                                                                                                                                       




                                                
               


                               
                                                                                                                                                                  
                                                
                                 

                                       
                                   
               


                               
                                                                                                                                                                  
                                                 
                                   
                                

                                       
               


                               
                                                                                                                                                                  




                                            
               


                               
                                                                                                                                                                  




                                            
               


                               
                                                                                                                                                                  
                          

                                           

               


                                     
                                                                                                                                                                  
            







                               
                                                                                                                                                                     






                                                                                                                                                                             
                                                                                                                                                                     






                                 
                                                                                                                                                                     
            
                                                                              

                                                 
                                                              


                                        
                                                                                                                                                                  
                                                                              

                                                 
                                                              


                                        
                                                                                                                                                                  
                                                                              

                                                 
                                                              


                                        
                                                                                                                                                                  
                                                                         

                                                 



                                                         
                                                                                                                                                                  



                                                                         


                                        
                                                                                                                                                                  

                                                  
                                                                            
                                 
                                                                                                                                                                 


                                    
                                                                                                                                                                  
              

                                                                                                                                                                       

             













                                                                                                         

                                                                                                                                                                       
           

                                                                                                                                                                         


                              


                                                                                                                                                                         


                                
                                                                                                                                                                       




                                                     
               


                               
                                                                                                                                                                  




                                                     
               


                               
                                                                                                                                                                  




                                            
               


                               
                                                                                                                                                                  


                                           

               


                                     
                                                                                                                                                                  







                                                                              
                                                                                                                                                                  






                                                                              
                                                                                                                                                                  






                                                                         
                                                                                                                                                                  
              

                                                                                                                                                                       

             
                                                                                                                                                                        

                                           


                                                

                                                                                                                                                                       






                                              
                                                                                                                                                                     
            

                                         


                                                                                                                                                                      


                                
                                                                                                                                                                  






                                               
                                                                                                                                                                     
            

                                              



                                                                                                                                                                      


                                 
                                                                                                                                                                  

                 

                                                                                                                                                                       

             
                                                                                                                                                                          
                 

                                          
                  

                            
                             








                                                                                            


                                                                                      



                                                   
                                                                                  
                                           







                                                                                                    












                                                               
                





                                          
     
              

                                                                                                                                                                       
                      







                                                                                                                                                                         


                               

                                                                                                                                                                       

                          

                                                                                                                                                                       

                          


                                                                                                                                                                       


                         
               


                                
                                                                                                                                                                  
                         
                   

                                                                                                                                                                     
              
                             
                      
                                                                                                                                                                  







                                  
                                                                                                                                                                     

                                     
                  



                                   
                                                                                                                                                                     






                                 
                                                                                                                                                                     

                              
                  


                                    
                                                                                                                                                                     
            
                                      
                                 
                                                                                                                                                                    

                                                   
                             
                   
               


                             


                                                                                                                                                                      


                                 

               


                             
                                                                                                                                                                  







                                 
                                                                                                                                                                     

                                                   
                  



                                           
                                                                                                                                                                     





                            
                                                                                                                                                                     






                                 
                                                                                                                                                                     
            
                                     
                                         
                                      
                   
               


                                


                                                                                                                                                                  


                                                            






                                                                                                                                                                               


                                                        
                                   
                   
               


                             


                                                                                                                                                                  


                                                            
                                            

                       
               


                                


                                                                                                                                                                  


                                                            




                                                                                                                                                                              


                                                             

                                                                                                                                                                      


                                        
                                                                                                                                                                  


                              
                                                                                                                                                                      


                                  
                                                                                                                                                                  



                                                                    
                                                                                
                   
               
                             

                                                                                                                                                                     


                                         
                                                                                                                                                                  







                                     
                                                                                                                                                                     

                                                   
                  



                                           
                                                                                                                                                                     





                            
                                                                                                                                                                     






                                 
                                                                                                                                                                     
            

                                                                     
                   
                                
                                

                                                                                                                                                                      
              
                             
                      


                                                                                                                                                                       








                                                 
                                                                                                                                                                     

                                              
                                                                                                                                                                    



                              
                                                                                                                                                                     






                                 
                                                                                                                                                                     

                                                                         
                                                       

                         
                                                                                                                                                                 


                                 


                                                                                                                                                                  


                                                                            
                                                

                          
               


                                 


                                                                                                                                                                  


                                                                        
                                               

                         
               


                                 


                                                                                                                                                                  




                                                                        

                                                                                                                                                                      


                            
                                                                                                                                                                  


                                            
                                                  
                                        

                         
               


                                 


                                                                                                                                                                  
                                                             
                                          
                                                              
                                         

                          
               


                                 


                                                                                                                                                                  
                                                                     







                                             
                                                                                                                                                                     

                                                      
                                                                                                                                                                        



                                           
                                                                                                                                                                     





                            
                                                                                                                                                                     






                                 
                                                                                                                                                                     
            
                                     


                                     

                                                                                                                                                                      


                            
                                                                                                                                                                  

                                            
                                          
                                                              
                                         

                          
               


                                 


                                                                                                                                                                  

                                                                      


                                                                 



                                                                                                                                                                             


                            
                                                                                                                                                                  

                                            
                                           
                                                     
                                          

                           
               


                                 


                                                                                                                                                                  

                                                    


                                                                 



                                                                                                                                                                             


                            
                                                                                                                                                                  





                                            
                                                                                                                                                                      


                                  
                                                                                                                                                                  

                                            
                   
                      
                                                                                                                                                                  
                         





                 
              

                                                                                                                                                                       

             







                                                                                         
                                                                                                                                                                  
                        

                                


                         


                               
                                                                          



                           
                                                                                                                                                                  
                        

                                











                                                        
                                                                                                                                                                  

                                                
               



                                        
                                                                                                                                                                  





                         
                                                                                                                                                                  
                        

                                


                         


                                                                                   

            
                        
                     
                     
                        



                 

                                  
               
                                    


                   
                      



              

                                                                                                                                                                       






                                        
                                                                                                                                                                  





                                         
                                                                                                                                                                  

                                                  


                                                    


                                


                                                                                                                                                                         


                              


                                                                                                                                                                         


                                
                                                                                                                                                                       
                      
                                                     
                   
                                     



                                     
                                                                                                                                                                  






                                                  
                                                                                                                                                                  
                                                  
                   
                                  



                                     
                                                                                                                                                                  
                                                     
                   
                                     



                                     
                                                                                                                                                                  






                                         
                                                                                                                                                                  






                                         
                                                                                                                                                                  






                                         
                                                                                                                                                                  

                                                   

                                       
                                      
               


                               
                                                                                                                                                                  
                                                   


                                       
                                      
               


                               
                                                                                                                                                                  
                                                   

                                       

                                      
               


                               
                                                                                                                                                                  
                          
                                                                                       
                   

               
                                             
                                     


                                 
                                                                                                                                                                  
            





                                             
                                                                                                                                                                  







                                       
                                                                                                                                                                     






                                                      
                                                                                                                                                                     






                                 
                                                                                                                                                                     





                                             
                                                                                                                                                                     

                                                                              
                   
                                                             
                                 



                                                
                                                                                                                                                                  
                                                                                 
                   
                                                             
                                    



                                                
                                                                                                                                                                  
                                                                     
                   
                                                             
                        



                                                
                                                                                                                                                                  
                                                                     
                   
                                                             
                        



                                                
                                                                                                                                                                  
              

                                                                                                                                                                       

             




















                                             

                                                                                                                                                                       






                                        
                                                                                                                                                                  





                                         
                                                                                                                                                                  

                                                  


                                                    


                                


                                                                                                                                                                         


                              


                                                                                                                                                                         


                                
                                                                                                                                                                       







                                                     
                                                                                                                                                                  






                                            
                                                                                                                                                                  






                                          
                                                                                                                                                                  






                                              
                                                                                                                                                                  






                                                     
                                                                                                                                                                  




                                                   
               


                               
                                                                                                                                                                  




                                                    
               


                               
                                                                                                                                                                  


                                                                                       

               




                                             
                                                                                                                                                                  






                                             
                                                                                                                                                                  







                                       
                                                                                                                                                                     






                                                      
                                                                                                                                                                     






                                 
                                                                                                                                                                     





                                             
                                                                                                                                                                     








                                                                        
                                                                                                                                                                  







                                                                        
                                                                                                                                                                  







                                                                                 
                                                                                                                                                                  
              

                                                                                                                                                                       






















                                                   

                                                                                                                                                                       






                                        
                                                                                                                                                                  





                                         
                                                                                                                                                                  

                                                  


                                                    


                                


                                                                                                                                                                         


                              


                                                                                                                                                                         


                                
                                                                                                                                                                       







                                                     
                                                                                                                                                                  






                                            
                                                                                                                                                                  






                                          
                                                                                                                                                                  






                                              
                                                                                                                                                                  






                                                    
                                                                                                                                                                  




                                                   
               


                               
                                                                                                                                                                  




                                                    
               


                               
                                                                                                                                                                  


                                                                                       

               




                                             
                                                                                                                                                                  






                                             
                                                                                                                                                                  







                                       
                                                                                                                                                                     






                                                      
                                                                                                                                                                     






                                 
                                                                                                                                                                     





                                             
                                                                                                                                                                     








                                                                        
                                                                                                                                                                  







                                                                        
                                                                                                                                                                  







                                                                                 
                                                                                                                                                                  
              

                                                                                                                                                                       

             






                                                                                                                                                  
                                                          
                                                                   

              

                                                                                                                                                                       
                      

               






                                                 
                                                                                                                                                                     
            

                                            


                                                                                                                                                                      


                                   








                                                                                                                                                                             

                                    
                                                                                                                                                                            
                                                                     







                                                                     
                                                                                                                                                                     
                                 

                     
                      


                                   


                                   


                                                                                                                                                                     

                                                      
                  



                                           
                                                                                                                                                                     





                            
                                                                                                                                                                     






                                  
                                                                                                                                                                     

                                                           
                                                                                                                                                                    



                                           
                                                                                                                                                                     





                            
                                                                                                                                                                     






                                
                                                                                                                                                                     







                                                     
                                                                                                                                                                     
            
                                                      
                   

                                                                                                                                                                     


                                                 
                                                                                                                                                                  
                                                               
                                                                                                                                                                  
                                      
                  
                         

                 
              

                                                                                                                                                                       



                                                                                                                                                     
                                                    
                                                                   
                                       
                                 

              

                                                                                                                                                                       
                      


                                                    
                                                  


                                                                                                                                                                             
                   
                                

                                
               
              
                       
                      




                                                                                                                                                                                
                                           









                                                                                                                                                                                                                           


                                     
                                                                                                                                                                     


                                  
                                                                                                                                                                  


                               
                                                                                                                                                                     


                                  
                                                                                                                                                                  
                     
                         


                 
              

                                                                                                                                                                       

             
                                                                                                                









                                                 
                                                     
                                 

              

                                                                                                                                                                       
                      



                                                                                                                                                                             
                                               



                                                                                                                                                                                 
                                          



                                                                                                                                                                                
                                          
                                                                                                                                                                                
                                        



                                                                                                                                                                                 
                                       
                                                                                                                                                                                
                                                                    


                                                                                                                                                                        

                         
               


                                 


                                                                                                                                                                  
                                                               
                        
                                                                                                                                                                            




                                                                                                                                                                            


                                                   
                                                                                                                                                                     


                                  
                                                                                                                                                                  


                               
                                                                                                                                                                     


                                  
                                                                                                                                                                  
                                   
                         

                 
              

                                                                                                                                                                       

             

                          

                                                                                                         

                                                                                                                                                                       
                      















                                                                                                                                                                              
                            
                                                                                                                                                                            

                                                                  

                                                                                                                                                                             
               
                          
                            
                                                                                                                                                                            

                                                                  

                                                                                                                                                                             
               
                          
                            
                                                                                                                                                                            

                                                                  

                                                                                                                                                                             
               
                          
                            
                                                                                                                                                                            

                                                                  

                                                                                                                                                                             
                     
                                                                                                                                                                   

                         



                 
              

                                                                                                                                                                       









                                              
                                                                                                                                                                  
                        

                                


                         




                                                                                           
                                    


                                                                                                                    

                                                                                                                                                                       

                              
                                                                                                                                                                     



                                                                                                                                                                          
                                                                                                                                                                  

                              
                                                                                                                                                                      



                                                                                                                                                                          
                                                                                                                                                                  

                              
                                                                                                                                                                      



                                                                                                                                                                          
                                                                                                                                                                  

                                    
                                                                                                                                                                      



                                                                                                                                                                          
                                                                                                                                                                  

                                                                         
                                                                                                                                                                      


                         
                                                                                                                                                                  

                 

                                                                                                                                                                       



                 

                                                                                                                                                                       

                                

                                                                                                                                                                                 









                                      
                                                                                                                                                                  







                               
                                                                                                                                                                     






                                                                                                                                                                             
                                                                                                                                                                     






                                 
                                                                                                                                                                     







                                              
                                                                                                                                                                  
              

                                                                                                                                                                       



                                                                                                       

                                                                                                                                                                       

                              
                                                                                                                                                                     



                                                                                                                                                                          
                                                                                                                                                                  

                                    
                                                                                                                                                                      



                                                                                                                                                                          
                                                                                                                                                                  

                              
                                                                                                                                                                      



                                                                                                                                                                          
                                                                                                                                                                  

                                    
                                                                                                                                                                      



                                                                                                                                                                          
                                                                                                                                                                  

                                                                         
                                                                                                                                                                      


                         
                                                                                                                                                                  

                 

                                                                                                                                                                       



                 

                                                                                                                                                                       

                                

                                                                                                                                                                                 









                                      
                                                                                                                                                                  







                               
                                                                                                                                                                     






                                                                                                                                                                             
                                                                                                                                                                     






                                 
                                                                                                                                                                     







                                                
                                                                                                                                                                  
              

                                                                                                                                                                       



                                                                                                                               

                                                                                                                                                                       

                              
                                                                                                                                                                     



                                                                                                                                                                          
                                                                                                                                                                  

                                    
                                                                                                                                                                      



                                                                                                                                                                          
                                                                                                                                                                  

                              
                                                                                                                                                                      



                                                                                                                                                                          
                                                                                                                                                                  

                                    
                                                                                                                                                                      



                                                                                                                                                                          
                                                                                                                                                                  

                                                                         
                                                                                                                                                                      


                         
                                                                                                                                                                  

                 

                                                                                                                                                                       



                 

                                                                                                                                                                       

                                



















                                                                                                                                                                                 


                                  
               
                      
               



                               
                                                                                                                                                                  







                               
                                                                                                                                                                     






                                                                                                                                                                             
                                                                                                                                                                     






                                 
                                                                                                                                                                     







                                         
                                                                                                                                                                  
              

                                                                                                                                                                       



                                                                                                                   

                                                                                                                                                                       

                              
                                                                                                                                                                     



                                                                                                                                                                          
                                                                                                                                                                  

                                    
                                                                                                                                                                      



                                                                                                                                                                          
                                                                                                                                                                  

                              
                                                                                                                                                                      



                                                                                                                                                                          
                                                                                                                                                                  

                                    
                                                                                                                                                                      



                                                                                                                                                                          
                                                                                                                                                                  

                                                                         
                                                                                                                                                                      


                         
                                                                                                                                                                  

                 

                                                                                                                                                                       



                 

                                                                                                                                                                       

                                










                                                                                                                                                                                 




                                    
               



                               
                                                                                                                                                                  







                               
                                                                                                                                                                     






                                                                                                                                                                             
                                                                                                                                                                     






                                 
                                                                                                                                                                     







                                              
                                                                                                                                                                  
              

                                                                                                                                                                       
             


                                                                                                                                

                                                                                                                                                                       

                              
                                                                                                                                                                     



                                                                                                                                                                          
                                                                                                                                                                  

                                    
                                                                                                                                                                      



                                                                                                                                                                          
                                                                                                                                                                  

                              
                                                                                                                                                                      



                                                                                                                                                                          
                                                                                                                                                                  

                              
                                                                                                                                                                      



                                                                                                                                                                          
                                                                                                                                                                  

                                                                         
                                                                                                                                                                      


                         
                                                                                                                                                                  

                 

                                                                                                                                                                       



                 

                                                                                                                                                                       

                                










                                                                                                                                                                                 




                                    
               



                               
                                                                                                                                                                  







                               
                                                                                                                                                                     






                                                                                                                                                                             
                                                                                                                                                                     






                                 
                                                                                                                                                                     







                                         
                                                                                                                                                                  
              

                                                                                                                                                                       
             
 
                                                  















                                                                                          

                                                                                                                                                                       
                      





                                                                                                                                                                 

                          
                                                                                                                                                                       







                                  
                                                                                                                                                                     

                                     
                                                                                                                                                                        



                                   
                                                                                                                                                                     






                                 
                                                                                                                                                                     
            

                           
                                                                                                                                                                     


                                 
                                                                                                                                                                  


                                 

                                                                                                                                                                     


                             
                                                                                                                                                                  







                                  
                                                                                                                                                                     
                                 

                     
                      


                                   


                                   


                                                                                                                                                                     

                                                   
                  



                                           
                                                                                                                                                                     





                            
                                                                                                                                                                     






                                 
                                                                                                                                                                     



                                         

                                      
                   
               


                                


                                                                                                                                                                  
                                         
                 


                                                    






                                                                                                                                                                               


                                                  






                                                                                                                                                                               



                                               

                                            

                       
               


                                


                                                                                                                                                                  
                                         
                 


                                                  


                                                                                                                                                                       
                   
               


                                         


                                                                                                                                                                      
                                   
               

                           
                                                                                                                                                                     


                                 
                                                                                                                                                                  
                      
                                                                                                                                                                  
                         


                 
              

                                                                                                                                                                       




                                         

                                                                                                                                                                       






                                        
                                                                                                                                                                  





                                         
                                                                                                                                                                  
                          
                                         




                                     

                                                                                                                                                                  


                                                            
               


                                    
                                                                                                                                                                  
              

                                                                                                                                                                       




                                         

                                                                                                                                                                       






                                        
                                                                                                                                                                  





                                         
                                                                                                                                                                  







                                           

                                                                                                                                                                  




                                     

                                                                                                                                                                  


                                                        
               


                                    
                                                                                                                                                                  
              

                                                                                                                                                                       




                                               

                                                                                                                                                                       






                                        
                                                                                                                                                                  





                                         
                                                                                                                                                                  







                                             

                                                                                                                                                                  




                                     

                                                                                                                                                                  


                                                      
               


                                    
                                                                                                                                                                  
              

                                                                                                                                                                       




                                         

                                                                                                                                                                       






                                        
                                                                                                                                                                  





                                         
                                                                                                                                                                  







                                             

                                                                                                                                                                  




                                     

                                                                                                                                                                  


                                                               
               


                                    
                                                                                                                                                                  
              

                                                                                                                                                                       




                                       

                                                                                                                                                                       






                                        
                                                                                                                                                                  





                                         
                                                                                                                                                                  







                                             

                                                                                                                                                                  




                                     

                                                                                                                                                                  


                                                               
               


                                    
                                                                                                                                                                  
              

                                                                                                                                                                       




                                             

                                                                                                                                                                       






                                        
                                                                                                                                                                  





                                         
                                                                                                                                                                  







                                               

                                                                                                                                                                  




                                     

                                                                                                                                                                  


                                                                
               


                                    
                                                                                                                                                                  
              

                                                                                                                                                                       




                                                            

                                                                                                                                                                       






                                        
                                                                                                                                                                  





                                         
                                                                                                                                                                  







                                                   

                                                                                                                                                                  




                                     

                                                                                                                                                                  


                                                     
               


                                    
                                                                                                                                                                  
              

                                                                                                                                                                       

             

       



                                                                           


            


































                                                                                


            













                                                                                                     
         




                                                                        
# Assign addresses (co-ordinates) to instructions (landmarks) in a program
# (landscape).
# Use the addresses assigned to:
#   a) replace labels
#   b) add segment headers with addresses and offsets correctly filled in
#
# To build:
#   $ ./subx translate 0*.subx apps/subx-common.subx apps/survey.subx  -o apps/survey
#
# The expected input is a stream of bytes with segment headers, comments and
# some interspersed labels.
#   $ cat x
#   == code 0x1
#   l1:
#   aa bb l1/imm8
#   cc dd l2/disp32
#   l2:
#   ee foo/imm32
#   == data 0x10
#   foo:
#     00
#
# The output is the stream of bytes without segment headers or label definitions,
# and with label references replaced with numeric values/displacements.
#
#   $ cat x  |./subx run apps/assort
#   ...ELF header bytes...
#   # ELF header above will specify that code segment begins at this offset
#   aa bb nn  # some computed address
#   cc dd nn nn nn nn  # some computed displacement
#   ee nn nn nn nn  # some computed address
#   # ELF header above will specify that data segment begins at this offset
#   00
#
# The ELF format has some persnickety constraints on the starting addresses of
# segments, so input headers are treated as guidelines and adjusted in the
# output.

== code
#   instruction                     effective address                                                   register    displacement    immediate
# . op          subop               mod             rm32          base        index         scale       r32
# . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes

Entry:
    # Heap = new-segment(Heap-size)
    # . . push args
    68/push  Heap/imm32
    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Heap-size/disp32                  # push *Heap-size
    # . . call
    e8/call  new-segment/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # initialize-trace-stream(256KB)
    # . . push args
    68/push  0x40000/imm32/256KB
    # . . call
    e8/call  initialize-trace-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp

    # run tests if necessary, convert stdin if not
    # . prolog
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # - if argc > 1 and argv[1] == "test", then return run_tests()
    # . argc > 1
    81          7/subop/compare     1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0/disp8         1/imm32           # compare *ebp
    7e/jump-if-lesser-or-equal  $run-main/disp8
    # . argv[1] == "test"
    # . . push args
    68/push  "test"/imm32
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    # . . call
    e8/call  kernel-string-equal?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . check result
    3d/compare-eax-and  1/imm32
    75/jump-if-not-equal  $run-main/disp8
    # . run-tests()
    e8/call  run-tests/disp32
    8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/ebx   Num-test-failures/disp32          # copy *Num-test-failures to ebx
    eb/jump  $main:end/disp8
$run-main:
    # - otherwise convert stdin
    # convert(Stdin, Stdout)
    # . . push args
    68/push  Stdout/imm32
    68/push  Stdin/imm32
    # . . call
    e8/call  convert/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write-stream(2/stderr, Trace-stream)
#?     # . . push args
#?     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . syscall(exit, 0)
    bb/copy-to-ebx  0/imm32
$main:end:
    b8/copy-to-eax  1/imm32/exit
    cd/syscall  0x80/imm8

# data structures:
#   segment-info: {address, file-offset, size}            (12 bytes)
#   segments: (address stream {string, segment-info})     (16 bytes per row)
#   label-info: {segment-name, segment-offset, address}   (12 bytes)
#   labels: (address stream {string, label-info})         (16 bytes per row)
# these are all inefficient; use sequential scans for lookups

convert:  # infile : (address buffered-file), out : (address buffered-file) -> <void>
    # pseudocode
    #   var in : (address stream byte) = stream(4096)
    #   slurp(infile, in)
    #   var segments = new-stream(10 rows, 16 bytes each)
    #   var labels = new-stream(Max-labels rows, 16 bytes each)
    #   compute-offsets(in, segments, labels)
    #   compute-addresses(segments, labels)
    #   rewind-stream(in)
    #   emit-output(in, out, segments, labels)
    #
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # . save registers
    51/push-ecx
    52/push-edx
    56/push-esi
    # var segments/ecx = stream(10 * 16)
    81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0xa0/imm32        # subtract from esp
    68/push  0xa0/imm32/length
    68/push  0/imm32/read
    68/push  0/imm32/write
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    # var labels/edx = stream(Max-labels * 16)
    # . data
    2b/subtract                     0/mod/indirect  5/rm32/.disp32            .             .           4/r32/esp   Max-labels/disp32                 # subtract *Max-labels from esp
    # . length
    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Max-labels/disp32                 # push *Max-labels
    # . read
    68/push  0/imm32/read
    # . write
    68/push  0/imm32/write
    89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
    # var in/esi = stream(Input-size * 1)
    # . data
    2b/subtract                     0/mod/indirect  5/rm32/.disp32            .             .           4/r32/esp   Input-size/disp32                 # subtract *Input-size from esp
    # . length
    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Input-size/disp32                 # push *Input-size
    # . read
    68/push  0/imm32/read
    # . write
    68/push  0/imm32/write
    89/copy                         3/mod/direct    6/rm32/esi    .           .             .           4/r32/esp   .               .                 # copy esp to esi
#?     # dump labels->write {{{
#?     # . write(2/stderr, "labels->write right after initialization: ")
#?     # . . push args
#?     68/push  "labels->write right after initialization: "/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . clear-stream(Stderr+4)
#?     # . . save eax
#?     50/push-eax
#?     # . . push args
#?     b8/copy-to-eax  Stderr/imm32
#?     05/add-to-eax  4/imm32
#?     50/push-eax
#?     # . . call
#?     e8/call  clear-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # . . restore eax
#?     58/pop-to-eax
#?     # . print-int32-buffered(Stderr, labels->write)
#?     # . . push args
#? $watch-1:
#?     ff          6/subop/push        0/mod/indirect  2/rm32/edx    .           .             .           .           .               .                 # push *edx
#?     68/push  Stderr/imm32
#?     # . . call
#?     e8/call  print-int32-buffered/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . flush(Stderr)
#?     # . . push args
#?     68/push  Stderr/imm32
#?     # . . call
#?     e8/call  flush/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # . write(2/stderr, "\n")
#?     # . . push args
#?     68/push  "\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
#?     # write(2/stderr, "slurp in\n") {{{
#?     # . . push args
#?     68/push  "slurp in\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
    # slurp(infile, in)
    # . . push args
    56/push-esi
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    # . . call
    e8/call  slurp/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # dump labels->write {{{
#?     # . write(2/stderr, "labels->write after slurp: ")
#?     # . . push args
#?     68/push  "labels->write after slurp: "/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . clear-stream(Stderr+4)
#?     # . . save eax
#?     50/push-eax
#?     # . . push args
#?     b8/copy-to-eax  Stderr/imm32
#?     05/add-to-eax  4/imm32
#?     50/push-eax
#?     # . . call
#?     e8/call  clear-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # . . restore eax
#?     58/pop-to-eax
#?     # . print-int32-buffered(Stderr, labels->write)
#?     # . . push args
#?     ff          6/subop/push        0/mod/indirect  2/rm32/edx    .           .             .           .           .               .                 # push *edx
#?     68/push  Stderr/imm32
#?     # . . call
#?     e8/call  print-int32-buffered/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . flush(Stderr)
#?     # . . push args
#?     68/push  Stderr/imm32
#?     # . . call
#?     e8/call  flush/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # . write(2/stderr, "\n")
#?     # . . push args
#?     68/push  "\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
#?     # dump in {{{
#?     # . write(2/stderr, "in: ")
#?     # . . push args
#?     68/push  "in: "/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # write-stream(2/stderr, in)
#?     # . . push args
#?     56/push-esi
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write(2/stderr, "$\n")
#?     # . . push args
#?     68/push  "$\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . rewind-stream(in)
#?     # . . push args
#?     56/push-esi
#?     # . . call
#?     e8/call  rewind-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # }}}
#?     # write(2/stderr, "compute-offsets\n") {{{
#?     # . . push args
#?     68/push  "compute-offsets\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
    # compute-offsets(in, segments, labels)
    # . . push args
    52/push-edx
    51/push-ecx
    56/push-esi
    # . . call
    e8/call  compute-offsets/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
#?     # write(2/stderr, "compute-addresses\n") {{{
#?     # . . push args
#?     68/push  "compute-addresses\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
    # compute-addresses(segments, labels)
    # . . push args
    52/push-edx
    51/push-ecx
    # . . call
    e8/call  compute-addresses/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # rewind-stream(in)
    # . . push args
    56/push-esi
    # . . call
    e8/call  rewind-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # write(2/stderr, "emit-output\n") {{{
#?     # . . push args
#?     68/push  "emit-output\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
#?     # dump *Trace-stream {{{
#?     # . write(2/stderr, "^")
#?     # . . push args
#?     68/push  "^"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write-stream(2/stderr, *Trace-stream)
#?     # . . push args
#?     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write(2/stderr, "$\n")
#?     # . . push args
#?     68/push  "$\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
#?     # dump labels->write {{{
#?     # . write(2/stderr, "labels->write after rewinding input: ")
#?     # . . push args
#?     68/push  "labels->write after rewinding input: "/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . clear-stream(Stderr+4)
#?     # . . save eax
#?     50/push-eax
#?     # . . push args
#?     b8/copy-to-eax  Stderr/imm32
#?     05/add-to-eax  4/imm32
#?     50/push-eax
#?     # . . call
#?     e8/call  clear-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # . . restore eax
#?     58/pop-to-eax
#?     # . print-int32-buffered(Stderr, labels)
#?     # . . push args
#?     ff          6/subop/push        0/mod/indirect  2/rm32/edx    .           .             .           .           .               .                 # push *edx
#?     68/push  Stderr/imm32
#?     # . . call
#?     e8/call  print-int32-buffered/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . flush(Stderr)
#?     # . . push args
#?     68/push  Stderr/imm32
#?     # . . call
#?     e8/call  flush/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # . write(2/stderr, "\n")
#?     # . . push args
#?     68/push  "\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
    # emit-output(in, out, segments, labels)
    # . . push args
    52/push-edx
    51/push-ecx
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
    56/push-esi
    # . . call
    e8/call  emit-output/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
    # flush(out)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
    # . . call
    e8/call  flush/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
$convert:end:
    # . reclaim locals
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x30a0/imm32      # add to esp
    # . restore registers
    5e/pop-to-esi
    5a/pop-to-edx
    59/pop-to-ecx
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-convert-computes-addresses:
    # input:
    #   == code 0x1
    #   Entry:
    #   ab x/imm32
    #   == data 0x1000
    #   x:
    #     01
    #
    # trace contains (in any order):
    #   label x is at address 0x1079
    #   segment code starts at address 0x74
    #   segment code has size 5
    #   segment data starts at address 0x1079
    #
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . clear-stream(_test-input-stream)
    # . . push args
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . clear-stream(_test-input-buffered-file+4)
    # . . push args
    b8/copy-to-eax  _test-input-buffered-file/imm32
    05/add-to-eax  4/imm32
    50/push-eax
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . clear-stream(_test-output-stream)
    # . . push args
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . clear-stream(_test-output-buffered-file+4)
    # . . push args
    b8/copy-to-eax  _test-output-buffered-file/imm32
    05/add-to-eax  4/imm32
    50/push-eax
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # initialize input
    # . write(_test-input-stream, "== code 0x1\n")
    # . . push args
    68/push  "== code 0x1\n"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . write(_test-input-stream, "Entry:\n")
    # . . push args
    68/push  "Entry:\n"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . write(_test-input-stream, "ab x/imm32\n")
    # . . push args
    68/push  "ab x/imm32\n"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . write(_test-input-stream, "== data 0x1000\n")
    # . . push args
    68/push  "== data 0x1000\n"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . write(_test-input-stream, "x:\n")
    # . . push args
    68/push  "x:\n"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . write(_test-input-stream, "01\n")
    # . . push args
    68/push  "01\n"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # convert(_test-input-buffered-file, _test-output-buffered-file)
    # . . push args
    68/push  _test-output-buffered-file/imm32
    68/push  _test-input-buffered-file/imm32
    # . . call
    e8/call  convert/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # check trace
#?     # dump *Trace-stream {{{
#?     # . write(2/stderr, "^")
#?     # . . push args
#?     68/push  "^"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write-stream(2/stderr, *Trace-stream)
#?     # . . push args
#?     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write(2/stderr, "$\n")
#?     # . . push args
#?     68/push  "$\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
    # . check-trace-contains("label 'x' is at address 0x00001079.", msg)
    # . . push args
    68/push  "F - test-convert-computes-addresses/0"/imm32
    68/push  "label 'x' is at address 0x00001079."/imm32
    # . . call
    e8/call  check-trace-contains/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . check-trace-contains("segment 'code' starts at address 0x00000074.", msg)
    # . . push args
    68/push  "F - test-convert-computes-addresses/1"/imm32
    68/push  "segment 'code' starts at address 0x00000074."/imm32
    # . . call
    e8/call  check-trace-contains/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . check-trace-contains("segment 'code' has size 0x00000005.", msg)
    # . . push args
    68/push  "F - test-convert-computes-addresses/2"/imm32
    68/push  "segment 'code' has size 0x00000005."/imm32
    # . . call
    e8/call  check-trace-contains/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . check-trace-contains("segment 'data' starts at address 0x00001079.", msg)
    # . . push args
    68/push  "F - test-convert-computes-addresses/3"/imm32
    68/push  "segment 'data' starts at address 0x00001079."/imm32
    # . . call
    e8/call  check-trace-contains/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

# global scratch space for compute-offsets in the data segment
== data

compute-offsets:file-offset:  # int
  0/imm32
compute-offsets:segment-offset:  # int
  0/imm32
compute-offsets:word-slice:
  0/imm32/start
  0/imm32/end
compute-offsets:segment-tmp:  # slice
  0/imm32/start
  0/imm32/end

== code

compute-offsets:  # in : (address stream), segments : (address stream {string, segment-info}), labels : (address stream {string, label-info})
    # skeleton:
    #   for lines in 'in'
    #     for words in line
    #       switch word
    #         case 1
    #         case 2
    #         ...
    #         default
    #
    # pseudocode:
    #   curr-segment-name : (address string) = 0
    #   var line = new-stream(512, 1)
    #   while true                                  # line loop
    #     clear-stream(line)
    #     read-line(in, line)
    #     if (line->write == 0) break               # end of file
    #     while true                                # word loop
    #       word-slice = next-word(line)
    #       if slice-empty?(word-slice)             # end of line
    #         break
    #       else if slice-starts-with?(word-slice, "#")  # comment
    #         break                                 # end of line
    #       else if slice-equal?(word-slice, "==")
    #         if curr-segment-name != 0
    #           seg = get-or-insert(segments, curr-segment-name)
    #           seg->size = *file-offset - seg->file-offset
    #           trace("segment '", curr-segment-name, "' has size ", seg->size)
    #         segment-tmp = next-word(line)
    #         curr-segment-name = slice-to-string(segment-tmp)
    #         if empty?(curr-segment-name)
    #           abort
    #         segment-tmp = next-word(line)
    #         if slice-empty?(segment-tmp)
    #           abort
    #         seg = get-or-insert(segments, curr-segment-name)
    #         seg->starting-address = parse-hex-int(segment-tmp)
    #         seg->file-offset = *file-offset
    #         trace("segment '", curr-segment-name, "' is at file offset ", seg->file-offset)
    #         segment-offset = 0
    #         break  (next line)
    #       else if is-label?(word-slice)
    #         strip trailing ':' from word-slice
    #         x : (address label-info) = get-or-insert(labels, name)
    #         x->segment-name = curr-segment-name
    #         trace("label '", word-slice, "' is in segment '", curr-segment-name, "'.")
    #         x->segment-offset = segment-offset
    #         trace("label '", word-slice, "' is at segment offset ", segment-offset, ".")
    #         # labels occupy no space, so no need to increment offsets
    #       else
    #         width = compute-width-of-slice(word-slice)
    #         *segment-offset += width
    #         *file-offset += width
    #
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    53/push-ebx
    56/push-esi
    57/push-edi
    # curr-segment-name/esi = 0
    31/xor                          3/mod/direct    6/rm32/esi    .           .             .           6/r32/esi   .               .                 # clear esi
    # file-offset = 0
    c7          0/subop/copy        0/mod/indirect  5/rm32/.disp32            .             .           .           compute-offsets:file-offset/disp32  0/imm32               # copy to *compute-offsets:word-slice
    # segment-offset = 0
    c7          0/subop/copy        0/mod/indirect  5/rm32/.disp32            .             .           .           compute-offsets:segment-offset/disp32  0/imm32            # copy to *compute-offsets:word-slice
    # line/ecx = new-stream(512, 1)
    # . eax = new-stream(512, 1)
    # . . push args
    68/push  1/imm32
    68/push  0x200/imm32
    68/push  Heap/imm32
    # . . call
    e8/call  new-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . line/ecx = eax
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy eax to ecx
$compute-offsets:line-loop:
    # clear-stream(line/ecx)
    51/push-ecx
    e8/call  clear-stream/disp32
    # . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # read-line(in, line/ecx)
    51/push-ecx
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    e8/call  read-line/disp32
    # . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # if (line->write == 0) break
    8b/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy *ecx to eax
    3d/compare-eax-and  0/imm32
    0f 84/jump-if-equal  $compute-offsets:break-line-loop/disp32
#?     # dump line {{{
#?     # . write(2/stderr, "LL: ")
#?     # . . push args
#?     68/push  "LL: "/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # write-stream(2/stderr, line)
#?     # . . push args
#?     51/push-ecx
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write(2/stderr, "$\n")
#?     # . . push args
#?     68/push  "$\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . rewind-stream(line)
#?     # . . push args
#?     51/push-ecx
#?     # . . call
#?     e8/call  rewind-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # }}}
$compute-offsets:word-loop:
    # edx = word-slice
    ba/copy-to-edx  compute-offsets:word-slice/imm32
    # next-word(line/ecx, word-slice/edx)
    52/push-edx
    51/push-ecx
    e8/call  next-word/disp32
    # . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # dump word-slice and maybe curr-segment-name {{{
#?     # . write(2/stderr, "w: ")
#?     # . . push args
#?     68/push  "w: "/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . clear-stream(Stderr+4)
#?     # . . save eax
#?     50/push-eax
#?     # . . push args
#?     b8/copy-to-eax  Stderr/imm32
#?     05/add-to-eax  4/imm32
#?     50/push-eax
#?     # . . call
#?     e8/call  clear-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # . . restore eax
#?     58/pop-to-eax
#?     # . write-slice-buffered(Stderr, word-slice)
#?     # . . push args
#?     52/push-edx
#?     68/push  Stderr/imm32
#?     # . . call
#?     e8/call  write-slice-buffered/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . flush(Stderr)
#?     # . . push args
#?     68/push  Stderr/imm32
#?     # . . call
#?     e8/call  flush/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # . write(2/stderr, "$\n")
#?     # . . push args
#?     68/push  "$\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . if (curr-segment-name == 0) print curr-segment-name
#?     81          7/subop/compare     3/mod/direct    6/rm32/esi    .           .             .           .           .               0/imm32           # compare esi
#?     74/jump-if-equal  $compute-offsets:case-empty/disp8
#?     # . write(2/stderr, "segment at start of word: ")
#?     # . . push args
#?     68/push  "segment at start of word: "/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write-buffered(Stderr, curr-segment-name)
#?     # . . push args
#?     56/push-esi
#?     68/push  Stderr/imm32
#?     # . . call
#?     e8/call  write-buffered/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . flush(Stderr)
#?     # . . push args
#?     68/push  Stderr/imm32
#?     # . . call
#?     e8/call  flush/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # . write(2/stderr, "$\n")
#?     # . . push args
#?     68/push  "$\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
$compute-offsets:case-empty:
    # if slice-empty?(word/edx) break
    # . eax = slice-empty?(word/edx)
    52/push-edx
    e8/call  slice-empty?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . if (eax != 0) break
    3d/compare-eax-and  0/imm32
    0f 85/jump-if-not-equal  $compute-offsets:line-loop/disp32
$compute-offsets:case-comment:
    # if slice-starts-with?(word-slice, "#") continue
    68/push  "#"/imm32
    52/push-edx
    e8/call  slice-starts-with?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . if (eax != 0) break
    3d/compare-eax-and  0/imm32
    0f 85/jump-if-not-equal  $compute-offsets:line-loop/disp32
$compute-offsets:case-segment-header:
    # if (!slice-equal?(word-slice/edx, "==")) goto next case
    # . eax = slice-equal?(word-slice/edx, "==")
    68/push  "=="/imm32
    52/push-edx
    e8/call  slice-equal?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . if (eax == 0) goto next case
    3d/compare-eax-and  0/imm32
    0f 84/jump-if-equal  $compute-offsets:case-label/disp32
    # if (curr-segment-name == 0) goto construct-next-segment
    81          7/subop/compare     3/mod/direct    6/rm32/esi    .           .             .           .           .               0/imm32           # compare esi
    74/jump-if-equal  $compute-offsets:construct-next-segment/disp8
    # seg/eax = get-or-insert(segments, curr-segment-name, row-size=16)
    # . . push args
    68/push  0x10/imm32/row-size
    56/push-esi
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
    # . . call
    e8/call  get-or-insert/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # seg->size = file-offset - seg->file-offset
    # . save ecx
    51/push-ecx
    # . ebx = *file-offset
    8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/ebx   compute-offsets:file-offset/disp32 # copy *file-offset to ebx
    # . ecx = seg->file-offset
    8b/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(eax+4) to ecx
    # . ebx -= ecx
    29/subtract                     3/mod/direct    3/rm32/ebx    .           .             .           1/r32/ecx   .               .                 # subtract ecx from ebx
    # . seg->size = ebx
    89/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           3/r32/ebx   8/disp8         .                 # copy ebx to *(eax+8)
    # . restore ecx
    59/pop-to-ecx
    # trace-sssns("segment '", curr-segment-name, "' has size ", seg->size, ".")
    # . . push args
    68/push  "."/imm32
    53/push-ebx
    68/push  "' has size "/imm32
    56/push-esi
    68/push  "segment '"/imm32
    # . . call
    e8/call  trace-sssns/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
$compute-offsets:construct-next-segment:
    # next-word(line/ecx, segment-tmp)
    68/push  compute-offsets:segment-tmp/imm32
    51/push-ecx
    e8/call  next-word/disp32
    # . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # dump curr-segment-name if not null (clobbering eax) {{{
#?     # . if (curr-segment-name == 0) goto update-curr-segment-name
#?     81          7/subop/compare     3/mod/direct    6/rm32/esi    .           .             .           .           .               0/imm32           # compare esi
#?     74/jump-if-equal  $compute-offsets:update-curr-segment-name/disp8
#?     # . write(2/stderr, "setting segment to: ")
#?     # . . push args
#?     68/push  "setting segment to: "/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . clear-stream(Stderr+4)
#?     # . . push args
#?     b8/copy-to-eax  Stderr/imm32
#?     05/add-to-eax  4/imm32
#?     50/push-eax
#?     # . . call
#?     e8/call  clear-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # . . restore eax
#?     58/pop-to-eax
#?     # . write-buffered(Stderr, curr-segment-name)
#?     # . . push args
#?     56/push-esi
#?     68/push  Stderr/imm32
#?     # . . call
#?     e8/call  write-buffered/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . flush(Stderr)
#?     # . . push args
#?     68/push  Stderr/imm32
#?     # . . call
#?     e8/call  flush/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # . write(2/stderr, "$\n")
#?     # . . push args
#?     68/push  "$\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
$compute-offsets:update-curr-segment-name:
    # curr-segment-name = slice-to-string(segment-tmp)
    # . eax = slice-to-string(Heap, segment-tmp)
    # . . push args
    68/push  compute-offsets:segment-tmp/imm32
    68/push  Heap/imm32
    # . . call
    e8/call  slice-to-string/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . curr-segment-name = eax
    89/copy                         3/mod/direct    6/rm32/esi    .           .             .           0/r32/eax   .               .                 # copy eax to esi
    # if empty?(curr-segment-name) abort
    # . if (eax == 0) abort
    3d/compare-eax-and  0/imm32
    0f 84/jump-if-equal  $compute-offsets:abort/disp32
    # next-word(line/ecx, segment-tmp)
    68/push  compute-offsets:segment-tmp/imm32
    51/push-ecx
    e8/call  next-word/disp32
    # . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # if slice-empty?(segment-tmp) abort
    # . eax = slice-empty?(segment-tmp)
    68/push  compute-offsets:segment-tmp/imm32
    e8/call  slice-empty?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . if (eax != 0) abort
    3d/compare-eax-and  0/imm32
    0f 85/jump-if-not-equal  $compute-offsets:abort/disp32
    # seg/ebx = get-or-insert(segments, curr-segment-name, row-size=16)
    # . . push args
    68/push  0x10/imm32/row-size
    56/push-esi
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
    # . . call
    e8/call  get-or-insert/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . ebx = eax
    89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to ebx
    # seg->address = parse-hex-int(segment-tmp)
    # . eax = parse-hex-int(segment-tmp)
    68/push  compute-offsets:segment-tmp/imm32
    e8/call  parse-hex-int/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . seg->address = eax
    89/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to *ebx
    # seg->file-offset = *file-offset
    8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   compute-offsets:file-offset/disp32 # copy *file-offset to eax
    89/copy                         1/mod/*+disp8   3/rm32/ebx    .           .             .           0/r32/eax   4/disp8         .                 # copy eax to *(ebx+4)
    # trace-sssns("segment '", curr-segment-name, "' is at file offset ", seg->file-offset, "")
    # . . push args
    68/push  "."/imm32
    50/push-eax
    68/push  "' is at file offset "/imm32
    56/push-esi
    68/push  "segment '"/imm32
    # . . call
    e8/call  trace-sssns/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
    # segment-offset = 0
    c7          0/subop/copy        0/mod/indirect  5/rm32/.disp32            .             .           .     compute-offsets:segment-offset/disp32  0/imm32           # copy to *segment-offset
    # break
    e9/jump $compute-offsets:line-loop/disp32
$compute-offsets:case-label:
    # if (!is-label?(word-slice/edx)) goto next case
    # . eax = is-label?(word-slice/edx)
    # . . push args
    52/push-edx
    # . . call
    e8/call  is-label?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . if (eax == 0) goto next case
    3d/compare-eax-and  0/imm32
    74/jump-if-equal  $compute-offsets:case-default/disp8
    # strip trailing ':' from word-slice
    ff          1/subop/decrement   1/mod/*+disp8   2/rm32/edx    .           .             .           .           4/disp8         .                 # decrement *(edx+4)
    # x/eax = leaky-get-or-insert-slice(labels, word-slice, row-size=16)
    # . . push args
    68/push  0x10/imm32/row-size
    52/push-edx
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
    # . . call
    e8/call  leaky-get-or-insert-slice/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
$compute-offsets:save-label-offset:
    # x->segment-name = curr-segment-name
    89/copy                         0/mod/indirect  0/rm32/eax    .           .             .           6/r32/esi   .               .                 # copy esi to *eax
    # trace-slsss("label '" word-slice/edx "' is in segment '" current-segment-name "'.")
    # . . push args
    68/push  "'."/imm32
    56/push-esi
    68/push  "' is in segment '"/imm32
    52/push-edx
    68/push  "label '"/imm32
    # . . call
    e8/call  trace-slsss/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
    # x->segment-offset = segment-offset
    # . ebx = segment-offset
    8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/ebx   compute-offsets:segment-offset/disp32  # copy *segment-offset to ebx
    # . x->segment-offset = ebx
    89/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           3/r32/ebx   4/disp8         .                 # copy ebx to *(eax+4)
    # trace-slsns("label '" word-slice/edx "' is at segment offset " *segment-offset/eax ".")
    # . . eax = file-offset
    b8/copy-to-eax compute-offsets:segment-offset/imm32
    # . . eax = *file-offset/eax
    8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           0/r32/eax   .               .                 # copy *eax to eax
    # . . push args
    68/push  "."/imm32
    50/push-eax
    68/push  "' is at segment offset "/imm32
    52/push-edx
    68/push  "label '"/imm32
    # . . call
    e8/call  trace-slsns/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
    # continue
    e9/jump  $compute-offsets:word-loop/disp32
$compute-offsets:case-default:
    # width/eax = compute-width-of-slice(word-slice)
    # . . push args
    52/push-edx
    # . . call
    e8/call compute-width-of-slice/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # segment-offset += width
    01/add                          0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   compute-offsets:segment-offset/disp32 # add eax to *segment-offset
    # file-offset += width
    01/add                          0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   compute-offsets:file-offset/disp32 # add eax to *file-offset
#?     # dump segment-offset {{{
#?     # . write(2/stderr, "segment-offset: ")
#?     # . . push args
#?     68/push  "segment-offset: "/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . clear-stream(Stderr+4)
#?     # . . save eax
#?     50/push-eax
#?     # . . push args
#?     b8/copy-to-eax  Stderr/imm32
#?     05/add-to-eax  4/imm32
#?     50/push-eax
#?     # . . call
#?     e8/call  clear-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # . . restore eax
#?     58/pop-to-eax
#?     # . print-int32-buffered(Stderr, segment-offset)
#?     # . . push args
#?     52/push-edx
#?     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           compute-offsets:segment-offset/disp32  # push *segment-offset
#?     68/push  Stderr/imm32
#?     # . . call
#?     e8/call  print-int32-buffered/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . flush(Stderr)
#?     # . . push args
#?     68/push  Stderr/imm32
#?     # . . call
#?     e8/call  flush/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # . write(2/stderr, "\n")
#?     # . . push args
#?     68/push  "\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
    e9/jump $compute-offsets:word-loop/disp32
$compute-offsets:break-line-loop:
    # seg/eax = get-or-insert(segments, curr-segment-name, row-size=16)
    # . . push args
    68/push  0x10/imm32/row-size
    56/push-esi
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
    # . . call
    e8/call  get-or-insert/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # seg->size = file-offset - seg->file-offset
    # . save ecx
    51/push-ecx
    # . ebx = *file-offset
    8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/ebx   compute-offsets:file-offset/disp32 # copy *file-offset to ebx
    # . ecx = seg->file-offset
    8b/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(eax+4) to ecx
    # . ebx -= ecx
    29/subtract                     3/mod/direct    3/rm32/ebx    .           .             .           1/r32/ecx   .               .                 # subtract ecx from ebx
    # . seg->size = ebx
    89/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           3/r32/ebx   8/disp8         .                 # copy ebx to *(eax+8)
    # . restore ecx
    59/pop-to-ecx
    # trace-sssns("segment '", curr-segment-name, "' has size ", seg->size, ".")
    # . trace-sssns("segment '", curr-segment-name, "' has size ", ebx, ".")
    # . . push args
    68/push  "."/imm32
    53/push-ebx
    68/push  "' has size "/imm32
    56/push-esi
    68/push  "segment '"/imm32
    # . . call
    e8/call  trace-sssns/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
$compute-offsets:end:
    # . reclaim locals
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

$compute-offsets:abort:
    # . _write(2/stderr, error)
    # . . push args
    68/push  "'==' must be followed by segment name and segment-start\n"/imm32
    68/push  2/imm32/stderr
    # . . call
    e8/call  _write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . syscall(exit, 1)
    bb/copy-to-ebx  1/imm32
    b8/copy-to-eax  1/imm32/exit
    cd/syscall  0x80/imm8
    # never gets here

test-compute-offsets:
    # input:
    #   == code 0x1
    #   ab x/imm32  # skip comment
    #   == data 0x1000
    #   00
    #   x:
    #     34
    #
    # trace contains (in any order):
    #   segment 'code' is at file offset 0x0.
    #   segment 'code' has size 0x5.
    #   segment 'data' is at file offset 0x5.
    #   segment 'data' has size 0x2.
    #   label 'x' is in segment 'data'.
    #   label 'x' is at segment offset 0x1.
    #
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . clear-stream(_test-input-stream)
    # . . push args
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # var segments/ecx = stream(2 * 16)
    81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x20/imm32        # subtract from esp
    68/push  0x20/imm32/length
    68/push  0/imm32/read
    68/push  0/imm32/write
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    # var labels/edx = stream(2 * 16)
    81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x20/imm32        # subtract from esp
    68/push  0x20/imm32/length
    68/push  0/imm32/read
    68/push  0/imm32/write
    89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
    # initialize input
    # . write(_test-input-stream, "== code 0x1\n")
    # . . push args
    68/push  "== code 0x1\n"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . write(_test-input-stream, "ab x/imm32  # skip comment\n")
    # . . push args
    68/push  "ab x/imm32  # skip comment\n"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . write(_test-input-stream, "== data 0x1000\n")
    # . . push args
    68/push  "== data 0x1000\n"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . write(_test-input-stream, "00\n")
    # . . push args
    68/push  "00\n"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . write(_test-input-stream, "x:\n")
    # . . push args
    68/push  "x:\n"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . write(_test-input-stream, "34\n")
    # . . push args
    68/push  "34\n"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # compute-offsets(_test-input-stream, segments, labels)
    # . . push args
    52/push-edx
    51/push-ecx
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  compute-offsets/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32        # add to esp
#?     # dump *Trace-stream {{{
#?     # . write(2/stderr, "^")
#?     # . . push args
#?     68/push  "^"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write-stream(2/stderr, *Trace-stream)
#?     # . . push args
#?     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write(2/stderr, "$\n")
#?     # . . push args
#?     68/push  "$\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
    # check trace
    # . check-trace-contains("segment 'code' is at file offset 0x00000000.", msg)
    # . . push args
    68/push  "F - test-compute-offsets/0"/imm32
    68/push  "segment 'code' is at file offset 0x00000000."/imm32
    # . . call
    e8/call  check-trace-contains/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . check-trace-contains("segment 'code' has size 0x00000005", msg)
    # . . push args
    68/push  "F - test-compute-offsets/1"/imm32
    68/push  "segment 'code' has size 0x00000005."/imm32
    # . . call
    e8/call  check-trace-contains/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . check-trace-contains("segment 'data' is at file offset 0x00000005.", msg)
    # . . push args
    68/push  "F - test-compute-offsets/2"/imm32
    68/push  "segment 'data' is at file offset 0x00000005."/imm32
    # . . call
    e8/call  check-trace-contains/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . check-trace-contains("segment 'data' has size 0x00000002.", msg)
    # . . push args
    68/push  "F - test-compute-offsets/3"/imm32
    68/push  "segment 'data' has size 0x00000002."/imm32
    # . . call
    e8/call  check-trace-contains/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . check-trace-contains("label 'x' is in segment 'data'.", msg)
    # . . push args
    68/push  "F - test-compute-offsets/4"/imm32
    68/push  "label 'x' is in segment 'data'."/imm32
    # . . call
    e8/call  check-trace-contains/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . check-trace-contains("label 'x' is at segment offset 0x00000001.", msg)
    # . . push args
    68/push  "F - test-compute-offsets/5"/imm32
    68/push  "label 'x' is at segment offset 0x00000001."/imm32
    # . . call
    e8/call  check-trace-contains/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . check-ints-equal(labels->write, 0x10, msg)
    # . . push args
    68/push  "F - test-compute-offsets-maintains-labels-write-index"/imm32
    68/push  0x10/imm32/1-entry
    ff          6/subop/push        0/mod/indirect  2/rm32/edx    .           .             .           .           .               .                 # push *edx
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

compute-addresses:  # segments : (address stream {string, segment-info}), labels : (address stream {string, label-info})
    # pseudocode:
    #   srow : (address segment-info) = segments->data
    #   max = segments->data + segments->write
    #   num-segments = segments->write / 16
    #   starting-offset = 0x34 + (num-segments * 0x20)
    #   while true
    #     if (srow >= max) break
    #     s->file-offset += starting-offset
    #     s->address &= 0xfffff000  # clear last 12 bits for p_align
    #     s->address += (s->file-offset & 0x00000fff)
    #     trace-sssns("segment " s->key " starts at address " s->address)
    #     srow += 16  # row-size
    #   lrow : (address label-info) = labels->data
    #   max = labels->data + labels->write
    #   while true
    #     if (lrow >= max) break
    #     seg-name : (address string) = lrow->segment-name
    #     label-seg : (address segment-info) = get(segments, seg-name)
    #     lrow->address = label-seg->address + lrow->segment-offset
    #     trace-sssns("label " lrow->key " is at address " lrow->address)
    #     lrow += 16  # row-size
    #
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    53/push-ebx
    56/push-esi
    57/push-edi
    # esi = segments
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
    # starting-offset/edi = 0x34 + (num-segments * 0x20)  # make room for ELF headers
    # . edi = segments->write / 16 (row-size)
    8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           7/r32/edi   .               .                 # copy *esi to edi
    c1/shift    5/subop/logic-right 3/mod/direct    7/rm32/edi    .           .             .           .           .               4/imm8            # shift edi right by 4 bits, while padding zeroes
    # . edi = (edi * 0x20) + 0x34
    c1/shift    4/subop/left        3/mod/direct    7/rm32/edi    .           .             .           .           .               5/imm8            # shift edi left by 5 bits
    81          0/subop/add         3/mod/direct    7/rm32/edi    .           .             .           .           .               0x34/imm32        # add to edi
    # srow/eax = segments->data
    8d/copy-address                 1/mod/*+disp8   6/rm32/esi    .           .             .           0/r32/eax   0xc/disp8       .                 # copy esi+12 to eax
    # max/ecx = segments->data + segments->write
    8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # copy *esi to ecx
    01/add                          3/mod/direct    1/rm32/ecx    .           .             .           6/r32/esi   .               .                 # add esi to ecx
$compute-addresses:segment-loop:
    # if (srow >= max) break
    39/compare                      3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # compare eax with ecx
    73/jump-if-greater-or-equal-unsigned  $compute-addresses:segment-break/disp8
    # srow->file-offset += starting-offset
    01/add                          1/mod/*+disp8   0/rm32/eax    .           .             .           7/r32/edi   8/disp8         .                 # add edi to *(eax+8)
    # clear last 12 bits of srow->address for p_align=0x1000
    # . edx = srow->address
    8b/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           2/r32/edx   4/disp8         .                 # copy *(eax+4) to edx
    # . edx &= 0xfffff000
    81          4/subop/and         3/mod/direct    2/rm32/edx    .           .             .           .           .               0xfffff000/imm32  # bitwise and of edx
    # update last 12 bits from srow->file-offset
    # . ebx = srow->file-offset
    8b/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           3/r32/ebx   8/disp8         .                 # copy *(eax+8) to ebx
    # . ebx &= 0xfff
    81          4/subop/and         3/mod/direct    3/rm32/ebx    .           .             .           .           .               0x00000fff/imm32  # bitwise and of ebx
    # . srow->address = edx | ebx
    09/or                           3/mod/direct    2/rm32/edx    .           .             .           3/r32/ebx   .               .                 # edx = bitwise OR with ebx
    89/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           2/r32/edx   4/disp8         .                 # copy edx to *(eax+4)
    # trace-sssns("segment " srow " starts at address " srow->address ".")
    # . . push args
    68/push  "."/imm32
    52/push-edx
    68/push  "' starts at address "/imm32
    ff          6/subop/push        0/mod/indirect  0/rm32/eax    .           .             .           .           .               .                 # push *eax
    68/push  "segment '"/imm32
    # . . call
    e8/call  trace-sssns/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
    # srow += 16  # size of row
    05/add-to-eax  0x10/imm32
    eb/jump  $compute-addresses:segment-loop/disp8
$compute-addresses:segment-break:
#?     # dump *Trace-stream {{{
#?     # . write(2/stderr, "^")
#?     # . . push args
#?     68/push  "^"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write-stream(2/stderr, *Trace-stream)
#?     # . . push args
#?     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write(2/stderr, "$\n")
#?     # . . push args
#?     68/push  "$\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
    # esi = labels
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   0xc/disp8       .                 # copy *(ebp+12) to esi
    # lrow/eax = labels->data
    8d/copy-address                 1/mod/*+disp8   6/rm32/esi    .           .             .           0/r32/eax   0xc/disp8       .                 # copy esi+12 to eax
    # max/ecx = labels->data + labels->write
    8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # copy *esi to ecx
    01/add                          3/mod/direct    1/rm32/ecx    .           .             .           6/r32/esi   .               .                 # add esi to ecx
$compute-addresses:label-loop:
    # if (lrow >= max) break
    39/compare                      3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # compare eax with ecx
    0f 83/jump-if-greater-or-equal-unsigned  $compute-addresses:end/disp32
#?     # dump lrow->key {{{
#?     # . write(2/stderr, "label: ")
#?     # . . push args
#?     68/push  "label: "/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write(2/stderr, lrow->key)
#?     # . . push args
#?     ff          6/subop/push        0/mod/indirect  0/rm32/eax    .           .             .           .           .               .                 # push *eax
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write(2/stderr, "$\n")
#?     # . . push args
#?     68/push  "$\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
    # seg-name/edx = lrow->segment-name
    8b/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           2/r32/edx   4/disp8         .                 # copy *eax to edx
#?     # dump seg-name {{{
#?     # . write(2/stderr, "compute-addresses: seg-name: ")
#?     # . . push args
#?     68/push  "seg-name: "/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write(2/stderr, seg-name)
#?     # . . push args
#?     52/push-edx
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write(2/stderr, "$\n")
#?     # . . push args
#?     68/push  "$\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
    # label-seg/edx : (address segment-info) = get(segments, seg-name, row-size=16, "segment table")
    # . save eax
    50/push-eax
    # . eax = get(segments, seg-name, row-size=16)
    # . . push args
    68/push  "segment table"/imm32
    68/push  0x10/imm32/row-size
    52/push-edx
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    # . . call
    e8/call  get/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
    # . edx = eax
    89/copy                         3/mod/direct    2/rm32/edx    .           .             .           0/r32/eax   .               .                 # copy eax to edx
    # . restore eax
    58/pop-to-eax
    # ebx = label-seg->address
    8b/copy                         0/mod/indirect  2/rm32/edx    .           .             .           3/r32/ebx   .               .                 # copy *edx to ebx
    # ebx += lrow->segment-offset
    03/add                          1/mod/*+disp8   0/rm32/eax    .           .             .           3/r32/ebx   8/disp8         .                 # add *(eax+8) to ebx
    # lrow->address = ebx
    89/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           3/r32/ebx   0xc/disp8       .                 # copy ebx to *(eax+12)
    # trace-sssns("label " lrow->key " is at address " lrow->address ".")
    # . . push args
    68/push  "."/imm32
    53/push-ebx
    68/push  "' is at address "/imm32
    ff          6/subop/push        0/mod/indirect  0/rm32/eax    .           .             .           .           .               .                 # push *eax
    68/push  "label '"/imm32
    # . . call
    e8/call  trace-sssns/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
    # lrow += 16  # size of row
    05/add-to-eax  0x10/imm32
    e9/jump  $compute-addresses:label-loop/disp32
$compute-addresses:end:
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-compute-addresses:
    # input:
    #   segments:
    #     - 'a': {0x1000, 0, 5}
    #     - 'b': {0x2018, 5, 1}
    #     - 'c': {0x5444, 6, 12}
    #   labels:
    #     - 'l1': {'a', 3, 0}
    #     - 'l2': {'b', 0, 0}
    #
    # trace contains in any order (comments in parens):
    #   segment 'a' starts at address 0x00001094.  (0x34 + 0x20 for each segment)
    #   segment 'b' starts at address 0x00002099.  (0x018 discarded)
    #   segment 'c' starts at address 0x0000509a.  (0x444 discarded)
    #   label 'l1' is at address 0x00001097.       (0x1094 + segment-offset 3)
    #   label 'l2' is at address 0x00002099.       (0x2099 + segment-offset 0)
    #
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . var segments/ecx = stream(10 * 16)
    81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0xa0/imm32        # subtract from esp
    68/push  0xa0/imm32/length
    68/push  0/imm32/read
    68/push  0/imm32/write
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    # . var labels/edx = stream(512 * 16)
    81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x2000/imm32      # subtract from esp
    68/push  0x2000/imm32/length
    68/push  0/imm32/read
    68/push  0/imm32/write
    89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
    # . stream-add4(segments, "a", 0x1000, 0, 5)
    68/push  5/imm32/segment-size
    68/push  0/imm32/file-offset
    68/push  0x1000/imm32/start-address
    68/push  "a"/imm32/segment-name
    51/push-ecx
    # . . call
    e8/call  stream-add4/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
    # . stream-add4(segments, "b", 0x2018, 5, 1)
    68/push  1/imm32/segment-size
    68/push  5/imm32/file-offset
    68/push  0x2018/imm32/start-address
    68/push  "b"/imm32/segment-name
    51/push-ecx
    # . . call
    e8/call  stream-add4/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
    # . stream-add4(segments, "c", 0x5444, 6, 12)
    68/push  0xc/imm32/segment-size
    68/push  6/imm32/file-offset
    68/push  0x5444/imm32/start-address
    68/push  "c"/imm32/segment-name
    51/push-ecx
    # . . call
    e8/call  stream-add4/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
    # . stream-add4(labels, "l1", "a", 3, 0)
    68/push  0/imm32/label-address
    68/push  3/imm32/segment-offset
    68/push  "a"/imm32/segment-name
    68/push  "l1"/imm32/label-name
    52/push-edx
    # . . call
    e8/call  stream-add4/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
    # . stream-add4(labels, "l2", "b", 0, 0)
    68/push  0/imm32/label-address
    68/push  0/imm32/segment-offset
    68/push  "b"/imm32/segment-name
    68/push  "l2"/imm32/label-name
    52/push-edx
    # . . call
    e8/call  stream-add4/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
    # component under test
    # . compute-addresses(segments, labels)
    # . . push args
    52/push-edx
    51/push-ecx
    # . . call
    e8/call  compute-addresses/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # checks
#?     # dump *Trace-stream {{{
#?     # . write(2/stderr, "^")
#?     # . . push args
#?     68/push  "^"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write-stream(2/stderr, *Trace-stream)
#?     # . . push args
#?     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write(2/stderr, "$\n")
#?     # . . push args
#?     68/push  "$\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
    # . check-trace-contains("segment 'a' starts at address 0x00001094.", msg)
    # . . push args
    68/push  "F - test-compute-addresses/0"/imm32
    68/push  "segment 'a' starts at address 0x00001094."/imm32
    # . . call
    e8/call  check-trace-contains/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . check-trace-contains("segment 'b' starts at address 0x00002099.", msg)
    # . . push args
    68/push  "F - test-compute-addresses/1"/imm32
    68/push  "segment 'b' starts at address 0x00002099."/imm32
    # . . call
    e8/call  check-trace-contains/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . check-trace-contains("segment 'c' starts at address 0x0000509a.", msg)
    # . . push args
    68/push  "F - test-compute-addresses/2"/imm32
    68/push  "segment 'c' starts at address 0x0000509a."/imm32
    # . . call
    e8/call  check-trace-contains/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . check-trace-contains("label 'l1' is at address 0x00001097.", msg)
    # . . push args
    68/push  "F - test-compute-addresses/3"/imm32
    68/push  "label 'l1' is at address 0x00001097."/imm32
    # . . call
    e8/call  check-trace-contains/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . check-trace-contains("label 'l2' is at address 0x00002099.", msg)
    # . . push args
    68/push  "F - test-compute-addresses/4"/imm32
    68/push  "label 'l2' is at address 0x00002099."/imm32
    # . . call
    e8/call  check-trace-contains/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . check-ints-equal(labels->write, 0x20, msg)
    # . . push args
    68/push  "F - test-compute-addresses/maintains-labels-write-index"/imm32
    68/push  0x20/imm32/2-entries
    ff          6/subop/push        0/mod/indirect  2/rm32/edx    .           .             .           .           .               .                 # push *edx
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-compute-addresses-large-segments:
    # input:
    #   segments:
    #     - 'a': {0x1000, 0, 0x5604}
    #     - 'b': {0x2018, 0x5604, 1}
    #   labels:
    #     - 'l1': {'a', 3, 0}
    #
    # trace contains in any order (comments in parens):
    #   segment 'a' starts at address 0x00001074.  (0x34 + 0x20 for each segment)
    #   segment 'b' starts at address 0x00002678.  (0x018 discarded; last 3 nibbles from 0x1074 + 0x5604)
    #   label 'l1' is at address 0x00001077.       (0x1074 + segment-offset 3)
    #
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . var segments/ecx = stream(10 * 16)
    81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0xa0/imm32        # subtract from esp
    68/push  0xa0/imm32/length
    68/push  0/imm32/read
    68/push  0/imm32/write
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    # . var labels/edx = stream(512 * 16)
    81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x2000/imm32      # subtract from esp
    68/push  0x2000/imm32/length
    68/push  0/imm32/read
    68/push  0/imm32/write
    89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
    # . stream-add4(segments, "a", 0x1000, 0, 0x5604)
    68/push  0x5604/imm32/segment-size
    68/push  0/imm32/file-offset
    68/push  0x1000/imm32/start-address
    68/push  "a"/imm32/segment-name
    51/push-ecx
    # . . call
    e8/call  stream-add4/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
    # . stream-add4(segments, "b", 0x2018, 0x5604, 1)
    68/push  1/imm32/segment-size
    68/push  0x5604/imm32/file-offset
    68/push  0x2018/imm32/start-address
    68/push  "b"/imm32/segment-name
    51/push-ecx
    # . . call
    e8/call  stream-add4/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
    # . stream-add4(labels, "l1", "a", 3, 0)
    68/push  0/imm32/label-address
    68/push  3/imm32/segment-offset
    68/push  "a"/imm32/segment-name
    68/push  "l1"/imm32/label-name
    52/push-edx
    # . . call
    e8/call  stream-add4/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
    # component under test
    # . compute-addresses(segments, labels)
    # . . push args
    52/push-edx
    51/push-ecx
    # . . call
    e8/call  compute-addresses/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # checks
    # . check-trace-contains("segment 'a' starts at address 0x00001074.", msg)
    # . . push args
    68/push  "F - test-compute-addresses-large-segments/0"/imm32
    68/push  "segment 'a' starts at address 0x00001074."/imm32
    # . . call
    e8/call  check-trace-contains/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . check-trace-contains("segment 'b' starts at address 0x00002678.", msg)
    # . . push args
    68/push  "F - test-compute-addresses-large-segments/1"/imm32
    68/push  "segment 'b' starts at address 0x00002678."/imm32
    # . . call
    e8/call  check-trace-contains/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . check-trace-contains("label 'l1' is at address 0x00001077.", msg)
    # . . push args
    68/push  "F - test-compute-addresses-large-segments/3"/imm32
    68/push  "label 'l1' is at address 0x00001077."/imm32
    # . . call
    e8/call  check-trace-contains/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

emit-output:  # in : (address stream), out : (address buffered-file), segments : (address stream {string, segment-info}), labels : (address stream {string, label-info})
    # pseudocode:
    #   emit-headers(out, segments, labels)
    #   emit-segments(in, out, segments, labels)
    #
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
#?     # write(2/stderr, "emit-headers\n") {{{
#?     # . . push args
#?     68/push  "emit-headers\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
    # emit-headers(out, segments, labels)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8       .                # push *(ebp+20)
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8       .                # push *(ebp+16)
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8        .                # push *(ebp+12)
    # . . call
    e8/call  emit-headers/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
#?     # write(2/stderr, "emit-segments\n") {{{
#?     # . . push args
#?     68/push  "emit-segments\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
    # emit-segments(in, out, segments, labels)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8       .                # push *(ebp+20)
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8       .                # push *(ebp+16)
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    # . . call
    e8/call  emit-segments/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
$emit-output:end:
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

emit-segments:  # in : (address stream), out : (address buffered-file), segments : (address stream {string, segment-info}), labels : (address stream {string, label-info})
    # pseudocode:
    #   var offset-of-next-instruction = 0
    #   var line = new-stream(512, 1)
    #   line-loop:
    #   while true
    #     clear-stream(line)
    #     read-line(in, line)
    #     if (line->write == 0) break               # end of file
    #     offset-of-next-instruction += num-bytes(line)
    #     while true
    #       var word-slice = next-word(line)
    #       if slice-empty?(word-slice)             # end of line
    #         break
    #       if slice-starts-with?(word-slice, "#")  # comment
    #         break
    #       if is-label?(word-slice)                # no need for label declarations anymore
    #         goto line-loop                        # don't insert empty lines
    #       if slice-equal?(word-slice, "==")       # no need for segment header lines
    #         goto line-loop                        # don't insert empty lines
    #       if length(word-slice) == 2
    #         write-slice-buffered(out, word-slice)
    #         write-buffered(out, " ")
    #         continue
    #       datum = next-token-from-slice(word-slice->start, word-slice->end, "/")
    #       info = get-slice(labels, datum)
    #       if !string-equal?(info->segment-name, "code")
    #         if has-metadata?(word-slice, "disp8")
    #           abort
    #         if has-metadata?(word-slice, "imm8")
    #           abort
    #         emit(out, info->address, 4)  # global variables always translate to absolute addresses
    #       # code segment cases
    #       else if has-metadata?(word-slice, "imm8")
    #         abort  # label should never go to imm8
    #       else if has-metadata?(word-slice, "imm32")
    #         emit(out, info->address, 4)
    #       else if has-metadata?(word-slice, "disp8")
    #         value = info->offset - offset-of-next-instruction
    #         emit(out, value, 1)
    #       else if has-metadata?(word-slice, "disp32")
    #         value = info->offset - offset-of-next-instruction
    #         emit(out, value, 4)
    #       else
    #         abort
    #     write-buffered(out, "\n")
    #
    # registers:
    #   line: ecx
    #   word-slice: edx
    #   offset-of-next-instruction: ebx
    #   datum: edi
    #   info: esi (inner loop only)
    #   temporaries: eax, esi (outer loop)
    #
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    53/push-ebx
    56/push-esi
    57/push-edi
    # var line/ecx : (address stream byte) = stream(512)
    81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x200/imm32       # subtract from esp
    68/push  0x200/imm32/length
    68/push  0/imm32/read
    68/push  0/imm32/write
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    # var word-slice/edx = {0, 0}
    68/push  0/imm32/end
    68/push  0/imm32/start
    89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
    # var datum/edi = {0, 0}
    68/push  0/imm32/end
    68/push  0/imm32/start
    89/copy                         3/mod/direct    7/rm32/edi    .           .             .           4/r32/esp   .               .                 # copy esp to edi
    # offset-of-next-instruction/ebx = 0
    31/xor                          3/mod/direct    3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # clear ebx
$emit-segments:line-loop:
    # clear-stream(line)
    # . . push args
    51/push-ecx
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # read-line(in, line)
    # . . push args
    51/push-ecx
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    # . . call
    e8/call  read-line/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # dump line {{{
#?     # . write(2/stderr, "LL: ")
#?     # . . push args
#?     68/push  "LL: "/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # write-stream(2/stderr, line)
#?     # . . push args
#?     51/push-ecx
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write(2/stderr, "$\n")
#?     # . . push args
#?     68/push  "$\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . rewind-stream(line)
#?     # . . push args
#?     51/push-ecx
#?     # . . call
#?     e8/call  rewind-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # }}}
$emit-segments:check-for-end-of-input:
    # if (line->write == 0) break
    81          7/subop/compare     0/mod/indirect  1/rm32/ecx    .           .             .           .           .               0/imm32           # compare *ecx
    0f 84/jump-if-equal  $emit-segments:end/disp32
    # offset-of-next-instruction += num-bytes(line)
    # . eax = num-bytes(line)
    # . . push args
    51/push-ecx
    # . . call
    e8/call  num-bytes/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . ebx += eax
    01/add                          3/mod/direct    3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # add eax to ebx
$emit-segments:word-loop:
    # next-word(line, word-slice)
    # . . push args
    52/push-edx
    51/push-ecx
    # . . call
    e8/call  next-word/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # dump word-slice {{{
#?     # . write(2/stderr, "w: ")
#?     # . . push args
#?     68/push  "w: "/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write-slice-buffered(Stderr, word-slice)
#?     # . . push args
#?     52/push-edx
#?     68/push  Stderr/imm32
#?     # . . call
#?     e8/call  write-slice-buffered/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . flush(Stderr)
#?     # . . push args
#?     68/push  Stderr/imm32
#?     # . . call
#?     e8/call  flush/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # . write(2/stderr, "$\n")
#?     # . . push args
#?     68/push  "$\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
$emit-segments:check-for-end-of-line:
    # if (slice-empty?(word-slice)) break
    # . eax = slice-empty?(word-slice)
    # . . push args
    52/push-edx
    # . . call
    e8/call  slice-empty?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . if (eax != 0) break
    3d/compare-eax-and  0/imm32
    0f 85/jump-if-not-equal  $emit-segments:next-line/disp32
$emit-segments:check-for-comment:
    # if (slice-starts-with?(word-slice, "#")) break
    # . start/esi = word-slice->start
    8b/copy                         0/mod/indirect  2/rm32/edx    .           .             .           6/r32/esi   .               .                 # copy *edx to esi
    # . c/eax = *start
    31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
    8a/copy-byte                    0/mod/indirect  6/rm32/esi    .           .             .           0/r32/AL    .               .                 # copy byte at *esi to AL
    # . if (eax == '#') break
    3d/compare-eax-and  0x23/imm32/hash
    0f 84/jump-if-equal  $emit-segments:next-line/disp32
$emit-segments:check-for-label:
    # if is-label?(word-slice) break
    # . eax = is-label?(word-slice)
    # . . push args
    52/push-edx
    # . . call
    e8/call  is-label?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . if (eax != 0) break
    3d/compare-eax-and  0/imm32
    0f 85/jump-if-not-equal  $emit-segments:line-loop/disp32
$emit-segments:check-for-segment-header:
    # if (slice-equal?(word-slice, "==")) break
    # . eax = slice-equal?(word-slice, "==")
    # . . push args
    68/push  "=="/imm32
    52/push-edx
    # . . call
    e8/call  slice-equal?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . if (eax != 0) break
    3d/compare-eax-and  0/imm32
    0f 85/jump-if-not-equal  $emit-segments:line-loop/disp32
$emit-segments:2-character:
    # if (length(word-slice) != 2) goto next check
    # . eax = length(word-slice)
    8b/copy                         1/mod/*+disp8   2/rm32/edx    .           .             .           0/r32/eax   4/disp8         .                 # copy *(edx+4) to eax
    2b/subtract                     0/mod/indirect  2/rm32/edx    .           .             .           0/r32/eax   .               .                 # subtract *edx from eax
    # . if (eax != 2) goto next check
    3d/compare-eax-and  2/imm32
    75/jump-if-not-equal  $emit-segments:check-metadata/disp8
    # write-slice-buffered(out, word-slice)
    # . . push args
    52/push-edx
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
    # . . call
    e8/call  write-slice-buffered/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # write-buffered(out, " ")
    # . . push args
    68/push  " "/imm32
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
    # . . call
    e8/call  write-buffered/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # continue
    e9/jump  $emit-segments:word-loop/disp32
$emit-segments:check-metadata:
    # - if we get here, 'word-slice' must be a label to be looked up
    # datum/edi = next-token-from-slice(word-slice->start, word-slice->end, "/")
    # . . push args
    57/push-edi
    68/push  0x2f/imm32/slash
    ff          6/subop/push        1/mod/*+disp8   2/rm32/edx    .           .             .           .           4/disp8         .                 # push *(edx+4)
    ff          6/subop/push        0/mod/indirect  2/rm32/edx    .           .             .           .           .               .                 # push *edx
    # . . call
    e8/call  next-token-from-slice/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
#?     # dump word-slice {{{
#?     # . write(2/stderr, "datum: ")
#?     # . . push args
#?     68/push  "datum: "/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write-slice-buffered(Stderr, word-slice)
#?     # . . push args
#?     57/push-edi
#?     68/push  Stderr/imm32
#?     # . . call
#?     e8/call  write-slice-buffered/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . flush(Stderr)
#?     # . . push args
#?     68/push  Stderr/imm32
#?     # . . call
#?     e8/call  flush/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # . write(2/stderr, "$\n")
#?     # . . push args
#?     68/push  "$\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
    # info/esi = get-slice(labels, datum, row-size=16, "label table")
    # . eax = get-slice(labels, datum, row-size=16, "label table")
    # . . push args
    68/push  "label table"/imm32
    68/push  0x10/imm32/row-size
    57/push-edi
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8      .                 # push *(ebp+20)
    # . . call
    e8/call  get-slice/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
    # . esi = eax
    89/copy                         3/mod/direct    6/rm32/esi    .           .             .           0/r32/eax   .               .                 # copy eax to esi
$emit-segments:check-global-variable:
#?     # dump info->segment-name {{{
#?     # . write(2/stderr, "aa: label segment: ")
#?     # . . push args
#?     68/push  "aa: label segment: "/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write(2/stderr, info->segment-name)
#?     # . . push args
#?     ff          6/subop/push        0/mod/indirect  6/rm32/esi    .           .             .           .           .               .                 # push *esi
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write(2/stderr, "$\n")
#?     # . . push args
#?     68/push  "$\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
    # if string-equal?(info->segment-name, "code") goto code label checks
    # . eax = string-equal?(info->segment-name, "code")
    # . . push args
    68/push  "code"/imm32
    ff          6/subop/push        0/mod/indirect  6/rm32/esi    .           .             .           .           .               .                 # push *esi
    # . . call
    e8/call  string-equal?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . if (eax != 0) goto code label checks
    3d/compare-eax-and  0/imm32
    0f 85/jump-if-not-equal  $emit-segments:check-code-label-for-imm8/disp32
$emit-segments:check-global-variable-for-disp8:
    # if has-metadata?(word-slice, "disp8") abort
    # . eax = has-metadata?(word-slice, "disp8")
    # . . push args
    68/push  "disp8"/imm32
    52/push-edx
    # . . call
    e8/call  has-metadata?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . if (eax != 0) abort
    3d/compare-eax-and  0/imm32
    0f 85/jump-if-not-equal  $emit-segments:global-variable-abort/disp32
$emit-segments:check-global-variable-for-imm8:
    # if has-metadata?(word-slice, "imm8") abort
    # . eax = has-metadata?(word-slice, "imm8")
    # . . push args
    68/push  "imm8"/imm32
    52/push-edx
    # . . call
    e8/call  has-metadata?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . if (eax != 0) abort
    3d/compare-eax-and  0/imm32
    0f 85/jump-if-not-equal  $emit-segments:global-variable-abort/disp32
$emit-segments:emit-global-variable:
    # emit-hex(out, info->address, 4)
    # . . push args
    68/push  4/imm32
    ff          6/subop/push        1/mod/*+disp8   6/rm32/esi    .           .             .           .           8/disp8         .                 # push *(esi+8)
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
    # . . call
    e8/call  emit-hex/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # continue
    e9/jump  $emit-segments:word-loop/disp32
$emit-segments:check-code-label-for-imm8:
    # if (has-metadata?(word-slice, "imm8")) abort
    # . eax = has-metadata?(edx, "imm8")
    # . . push args
    68/push  "imm8"/imm32
    52/push-edx
    # . . call
    e8/call  has-metadata?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . if (eax != 0) abort
    3d/compare-eax-and  0/imm32
    0f 85/jump-if-not-equal  $emit-segments:imm8-abort/disp32
$emit-segments:check-code-label-for-imm32:
    # if (!has-metadata?(word-slice, "imm32")) goto next check
    # . eax = has-metadata?(edx, "imm32")
    # . . push args
    68/push  "imm32"/imm32
    52/push-edx
    # . . call
    e8/call  has-metadata?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . if (eax == 0) goto next check
    3d/compare-eax-and  0/imm32
    74/jump-if-equal  $emit-segments:check-code-label-for-disp8/disp8
#?     # dump info->address {{{
#?     # . write(2/stderr, "info->address: ")
#?     # . . push args
#?     68/push  "info->address: "/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . print-int32-buffered(Stderr, info->address)
#?     # . . push args
#?     ff          6/subop/push        1/mod/*+disp8   6/rm32/esi    .           .             .           .           8/disp8         .                 # push *(esi+8)
#?     68/push  Stderr/imm32
#?     # . . call
#?     e8/call  print-int32-buffered/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . flush(Stderr)
#?     # . . push args
#?     68/push  Stderr/imm32
#?     # . . call
#?     e8/call  flush/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # . write(2/stderr, "$\n")
#?     # . . push args
#?     68/push  "$\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
$emit-segments:emit-code-label-imm32:
    # emit-hex(out, info->address, 4)
    # . . push args
    68/push  4/imm32
    ff          6/subop/push        1/mod/*+disp8   6/rm32/esi    .           .             .           .           8/disp8         .                 # push *(esi+8)
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
    # . . call
    e8/call  emit-hex/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # continue
    e9/jump  $emit-segments:word-loop/disp32
$emit-segments:check-code-label-for-disp8:
    # if (!has-metadata?(word-slice, "disp8")) goto next check
    # . eax = has-metadata?(edx, "disp8")
    # . . push args
    68/push  "disp8"/imm32
    52/push-edx
    # . . call
    e8/call  has-metadata?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . if (eax == 0) goto next check
    3d/compare-eax-and  0/imm32
    74/jump-if-equal  $emit-segments:check-code-label-for-disp32/disp8
$emit-segments:emit-code-label-disp8:
    # emit-hex(out, info->offset - offset-of-next-instruction, 1)
    # . . push args
    68/push  1/imm32
    8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           0/r32/eax   4/disp8         .                 # copy *(esi+4) to eax
    29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # subtract ebx from eax
    50/push-eax
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
    # . . call
    e8/call  emit-hex/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # continue
    e9/jump  $emit-segments:word-loop/disp32
$emit-segments:check-code-label-for-disp32:
    # if (!has-metadata?(word-slice, "disp32")) abort
    # . eax = has-metadata?(edx, "disp32")
    # . . push args
    68/push  "disp32"/imm32
    52/push-edx
    # . . call
    e8/call  has-metadata?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . if (eax == 0) abort
    3d/compare-eax-and  0/imm32
    0f 84/jump-if-equal  $emit-segments:abort/disp32
$emit-segments:emit-code-label-disp32:
    # emit-hex(out, info->offset - offset-of-next-instruction, 4)
    # . . push args
    68/push  4/imm32
    8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           0/r32/eax   4/disp8         .                 # copy *(esi+4) to eax
    29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # subtract ebx from eax
    50/push-eax
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
    # . . call
    e8/call  emit-hex/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # continue
    e9/jump  $emit-segments:word-loop/disp32
$emit-segments:next-line:
    # write-buffered(out, "\n")
    # . . push args
    68/push  Newline/imm32
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
    # . . call
    e8/call  write-buffered/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # loop
    e9/jump  $emit-segments:line-loop/disp32
$emit-segments:end:
    # . reclaim locals
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x21c/imm32       # add to esp
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

$emit-segments:global-variable-abort:
    # . _write(2/stderr, error)
    # . . push args
    68/push  "emit-segments: must refer to global variables with /disp32 or /imm32"/imm32
    68/push  2/imm32/stderr
    # . . call
    e8/call  _write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . syscall(exit, 1)
    bb/copy-to-ebx  1/imm32
    b8/copy-to-eax  1/imm32/exit
    cd/syscall  0x80/imm8
    # never gets here

$emit-segments:imm8-abort:
    # . _write(2/stderr, error)
    # . . push args
    68/push  "emit-segments: cannot refer to code labels with /imm8"/imm32
    68/push  2/imm32/stderr
    # . . call
    e8/call  _write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . syscall(exit, 1)
    bb/copy-to-ebx  1/imm32
    b8/copy-to-eax  1/imm32/exit
    cd/syscall  0x80/imm8
    # never gets here

$emit-segments:abort:
    # print(stderr, "missing metadata in " word-slice)
    # . _write(2/stderr, "missing metadata in word ")
    # . . push args
    68/push  "emit-segments: missing metadata in "/imm32
    68/push  2/imm32/stderr
    # . . call
    e8/call  _write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . write-slice-buffered(Stderr, word-slice)
    # . . push args
    52/push-edx
    68/push  Stderr/imm32
    # . . call
    e8/call  write-slice-buffered/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . flush(Stderr)
    # . . push args
    68/push  Stderr/imm32
    # . . call
    e8/call  flush/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . syscall(exit, 1)
    bb/copy-to-ebx  1/imm32
    b8/copy-to-eax  1/imm32/exit
    cd/syscall  0x80/imm8
    # never gets here

test-emit-segments-global-variable:
    # global variables always convert to absolute addresses, regardless of metadata
    #
    # input:
    #   in:
    #     == code 0x1000
    #     ab cd ef gh
    #     ij x/disp32
    #     == data 0x2000
    #     00
    #     x:
    #       34
    #   segments:
    #     - 'code': {0x1074, 0, 9}
    #     - 'data': {0x2079, 5, 2}
    #   labels:
    #     - 'x': {'data', 1, 0x207a}
    #
    # output:
    #   ab cd ef gh
    #   ij 7a 20 00 00
    #   00
    #   34
    #
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . clear-stream(_test-input-stream)
    # . . push args
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . clear-stream(_test-output-stream)
    # . . push args
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . clear-stream(_test-output-buffered-file+4)
    # . . push args
    b8/copy-to-eax  _test-output-buffered-file/imm32
    05/add-to-eax  4/imm32
    50/push-eax
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . var segments/ecx = stream(10 * 16)
    81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0xa0/imm32        # subtract from esp
    68/push  0xa0/imm32/length
    68/push  0/imm32/read
    68/push  0/imm32/write
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    # . var labels/edx = stream(512 * 16)
    81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x2000/imm32      # subtract from esp
    68/push  0x2000/imm32/length
    68/push  0/imm32/read
    68/push  0/imm32/write
    89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
    # initialize input
    # . write(_test-input-stream, "== code 0x1000\n")
    # . . push args
    68/push  "== code 0x1000\n"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . write(_test-input-stream, "ab cd ef gh\n")
    # . . push args
    68/push  "ab cd ef gh\n"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . write(_test-input-stream, "ij x/disp32\n")
    # . . push args
    68/push  "ij x/disp32\n"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . write(_test-input-stream, "== data 0x2000\n")
    # . . push args
    68/push  "== data 0x2000\n"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . write(_test-input-stream, "00\n")
    # . . push args
    68/push  "00\n"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . write(_test-input-stream, "x:\n")
    # . . push args
    68/push  "x:\n"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . write(_test-input-stream, "34\n")
    # . . push args
    68/push  "34\n"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . stream-add4(segments, "code", 0x1074, 0, 9)
    68/push  9/imm32/segment-size
    68/push  0/imm32/file-offset
    68/push  0x1074/imm32/start-address
    68/push  "code"/imm32/segment-name
    51/push-ecx
    # . . call
    e8/call  stream-add4/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
    # . stream-add4(segments, "data", 0x2079, 5, 2)
    68/push  1/imm32/segment-size
    68/push  5/imm32/file-offset
    68/push  0x2079/imm32/start-address
    68/push  "data"/imm32/segment-name
    51/push-ecx
    # . . call
    e8/call  stream-add4/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
    # . stream-add4(labels, "x", "data", 1, 0x207a)
    68/push  0x207a/imm32/label-address
    68/push  1/imm32/segment-offset
    68/push  "data"/imm32/segment-name
    68/push  "x"/imm32/label-name
    52/push-edx
    # . . call
    e8/call  stream-add4/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
    # component under test
    # . emit-segments(_test-input-stream, _test-output-buffered-file, segments, labels)
    # . . push args
    52/push-edx
    51/push-ecx
    68/push  _test-output-buffered-file/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  emit-segments/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
    # checks
    # . flush(_test-output-buffered-file)
    # . . push args
    68/push  _test-output-buffered-file/imm32
    # . . call
    e8/call  flush/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # dump output {{{
#?     # . write(2/stderr, "result: ^")
#?     # . . push args
#?     68/push  "result: ^"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write-stream(2/stderr, _test-output-stream)
#?     # . . push args
#?     68/push  _test-output-stream/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write(2/stderr, "$\n")
#?     # . . push args
#?     68/push  "$\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . rewind-stream(_test-output-stream)
#?     # . . push args
#?     68/push  _test-output-stream/imm32
#?     # . . call
#?     e8/call  rewind-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # }}}
    # . check-next-stream-line-equal(_test-output-stream, "ab cd ef gh ", msg)
    # . . push args
    68/push  "F - test-emit-segments-global-variable/0"/imm32
    68/push  "ab cd ef gh "/imm32
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  check-next-stream-line-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . check-next-stream-line-equal(_test-output-stream, "ij 7a 20 00 00 ", msg)
    # . . push args
    68/push  "F - test-emit-segments-global-variable/1"/imm32
    68/push  "ij 7a 20 00 00 "/imm32
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  check-next-stream-line-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . check-next-stream-line-equal(_test-output-stream, "00 ", msg)
    # . . push args
    68/push  "F - test-emit-segments-global-variable/2"/imm32
    68/push  "00 "/imm32
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  check-next-stream-line-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . check-next-stream-line-equal(_test-output-stream, "34 ", msg)
    # . . push args
    68/push  "F - test-emit-segments-global-variable/3"/imm32
    68/push  "34 "/imm32
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  check-next-stream-line-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-emit-segments-code-label:
    # labels usually convert to displacements
    #
    # input:
    #   in:
    #     == code 0x1000
    #     ab cd
    #     l1:
    #       ef gh
    #       ij l1/disp32
    #   segments:
    #     - 'code': {0x1054, 0, 9}
    #   labels:
    #     - 'l1': {'code', 2, 0x1056}
    #
    # output:
    #   ab cd
    #   ef gh
    #   ij f9 ff ff ff  # -7
    #
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . clear-stream(_test-input-stream)
    # . . push args
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . clear-stream(_test-output-stream)
    # . . push args
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . clear-stream(_test-output-buffered-file+4)
    # . . push args
    b8/copy-to-eax  _test-output-buffered-file/imm32
    05/add-to-eax  4/imm32
    50/push-eax
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . var segments/ecx = stream(10 * 16)
    81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0xa0/imm32        # subtract from esp
    68/push  0xa0/imm32/length
    68/push  0/imm32/read
    68/push  0/imm32/write
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    # . var labels/edx = stream(512 * 16)
    81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x2000/imm32      # subtract from esp
    68/push  0x2000/imm32/length
    68/push  0/imm32/read
    68/push  0/imm32/write
    89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
    # initialize input
    # . write(_test-input-stream, "== code 0x1000\n")
    # . . push args
    68/push  "== code 0x1000\n"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . write(_test-input-stream, "ab cd\n")
    # . . push args
    68/push  "ab cd\n"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . write(_test-input-stream, "l1:\n")
    # . . push args
    68/push  "l1:\n"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . write(_test-input-stream, "  ef gh\n")
    # . . push args
    68/push  "  ef gh\n"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . write(_test-input-stream, "  ij l1/disp32\n")
    # . . push args
    68/push  "  ij l1/disp32\n"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . stream-add4(segments, "code", 0x1054, 0, 9)
    68/push  9/imm32/segment-size
    68/push  0/imm32/file-offset
    68/push  0x1054/imm32/start-address
    68/push  "code"/imm32/segment-name
    51/push-ecx
    # . . call
    e8/call  stream-add4/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
    # . stream-add4(labels, "l1", "code", 2, 0x1056)
    68/push  0x1056/imm32/label-address
    68/push  2/imm32/segment-offset
    68/push  "code"/imm32/segment-name
    68/push  "l1"/imm32/label-name
    52/push-edx
    # . . call
    e8/call  stream-add4/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
    # component under test
    # . emit-segments(_test-input-stream, _test-output-buffered-file, segments, labels)
    # . . push args
    52/push-edx
    51/push-ecx
    68/push  _test-output-buffered-file/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  emit-segments/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
    # checks
    # . flush(_test-output-buffered-file)
    # . . push args
    68/push  _test-output-buffered-file/imm32
    # . . call
    e8/call  flush/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # dump output {{{
#?     # . write(2/stderr, "result: ^")
#?     # . . push args
#?     68/push  "result: ^"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write-stream(2/stderr, _test-output-stream)
#?     # . . push args
#?     68/push  _test-output-stream/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write(2/stderr, "$\n")
#?     # . . push args
#?     68/push  "$\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . rewind-stream(_test-output-stream)
#?     # . . push args
#?     68/push  _test-output-stream/imm32
#?     # . . call
#?     e8/call  rewind-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # }}}
    # . check-next-stream-line-equal(_test-output-stream, "ab cd ", msg)
    # . . push args
    68/push  "F - test-emit-segments-code-label/0"/imm32
    68/push  "ab cd "/imm32
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  check-next-stream-line-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . check-next-stream-line-equal(_test-output-stream, "ef gh ", msg)
    # . . push args
    68/push  "F - test-emit-segments-code-label/1"/imm32
    68/push  "ef gh "/imm32
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  check-next-stream-line-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . check-next-stream-line-equal(_test-output-stream, "ij f9 ff ff ff ", msg)
    # . . push args
    68/push  "F - test-emit-segments-code-label/2"/imm32
    68/push  "ij f9 ff ff ff "/imm32
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  check-next-stream-line-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-emit-segments-code-label-absolute:
    # labels can also convert to absolute addresses
    #
    # input:
    #   in:
    #     == code 0x1000
    #     ab cd
    #     l1:
    #       ef gh
    #       ij l1/imm32
    #   segments:
    #     - 'code': {0x1054, 0, 9}
    #   labels:
    #     - 'l1': {'code', 2, 0x1056}
    #
    # output:
    #   ab cd
    #   ef gh
    #   ij 56 10 00 00
    #
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . clear-stream(_test-input-stream)
    # . . push args
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . clear-stream(_test-output-stream)
    # . . push args
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . clear-stream(_test-output-buffered-file+4)
    # . . push args
    b8/copy-to-eax  _test-output-buffered-file/imm32
    05/add-to-eax  4/imm32
    50/push-eax
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . var segments/ecx = stream(10 * 16)
    81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0xa0/imm32        # subtract from esp
    68/push  0xa0/imm32/length
    68/push  0/imm32/read
    68/push  0/imm32/write
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    # . var labels/edx = stream(512 * 16)
    81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x2000/imm32      # subtract from esp
    68/push  0x2000/imm32/length
    68/push  0/imm32/read
    68/push  0/imm32/write
    89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
    # initialize input
    # . write(_test-input-stream, "== code 0x1000\n")
    # . . push args
    68/push  "== code 0x1000\n"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . write(_test-input-stream, "ab cd\n")
    # . . push args
    68/push  "ab cd\n"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . write(_test-input-stream, "l1:\n")
    # . . push args
    68/push  "l1:\n"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . write(_test-input-stream, "  ef gh\n")
    # . . push args
    68/push  "  ef gh\n"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . write(_test-input-stream, "  ij l1/imm32\n")
    # . . push args
    68/push  "  ij l1/imm32\n"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . stream-add4(segments, "code", 0x1054, 0, 9)
    68/push  9/imm32/segment-size
    68/push  0/imm32/file-offset
    68/push  0x1054/imm32/start-address
    68/push  "code"/imm32/segment-name
    51/push-ecx
    # . . call
    e8/call  stream-add4/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
    # . stream-add4(labels, "l1", "code", 2, 0x1056)
    68/push  0x1056/imm32/label-address
    68/push  2/imm32/segment-offset
    68/push  "code"/imm32/segment-name
    68/push  "l1"/imm32/label-name
    52/push-edx
    # . . call
    e8/call  stream-add4/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
    # component under test
    # . emit-segments(_test-input-stream, _test-output-buffered-file, segments, labels)
    # . . push args
    52/push-edx
    51/push-ecx
    68/push  _test-output-buffered-file/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  emit-segments/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
    # checks
    # . flush(_test-output-buffered-file)
    # . . push args
    68/push  _test-output-buffered-file/imm32
    # . . call
    e8/call  flush/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # dump output {{{
#?     # . write(2/stderr, "result: ^")
#?     # . . push args
#?     68/push  "result: ^"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write-stream(2/stderr, _test-output-stream)
#?     # . . push args
#?     68/push  _test-output-stream/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write(2/stderr, "$\n")
#?     # . . push args
#?     68/push  "$\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . rewind-stream(_test-output-stream)
#?     # . . push args
#?     68/push  _test-output-stream/imm32
#?     # . . call
#?     e8/call  rewind-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # }}}
    # . check-next-stream-line-equal(_test-output-stream, "ab cd ", msg)
    # . . push args
    68/push  "F - test-emit-segments-code-label-absolute/0"/imm32
    68/push  "ab cd "/imm32
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  check-next-stream-line-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . check-next-stream-line-equal(_test-output-stream, "ef gh ", msg)
    # . . push args
    68/push  "F - test-emit-segments-code-label-absolute/1"/imm32
    68/push  "ef gh "/imm32
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  check-next-stream-line-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . check-next-stream-line-equal(_test-output-stream, "ij f9 ff ff ff ", msg)
    # . . push args
    68/push  "F - test-emit-segments-code-label-absolute/2"/imm32
    68/push  "ij 56 10 00 00 "/imm32
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  check-next-stream-line-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

emit-headers:  # out : (address buffered-file), segments : (address stream {string, segment-info}), labels : (address stream {string, label-info})
    # pseudocode:
    #   emit-elf-header(out, segments, labels)
    #   curr-segment = segments->data
    #   max = segments->data + segments->write
    #   while true
    #     if (curr-segment >= max) break
    #     emit-elf-program-header-entry(out, curr-segment)
    #     curr-segment += 16                        # size of a row
    #
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # . save registers
    50/push-eax
    51/push-ecx
#?     # write(2/stderr, "emit-elf-header\n") {{{
#?     # . . push args
#?     68/push  "emit-elf-header\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
    # emit-elf-header(out, segments, labels)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    # . . call
    e8/call  emit-elf-header/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # eax = segments
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   0xc/disp8       .                 # copy *(ebp+12) to eax
    # ecx = segments->write
    8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    # curr-segment/eax = segments->data
    8d/copy-address                 1/mod/*+disp8   0/rm32/eax    .           .             .           0/r32/eax   0xc/disp8       .                 # copy eax+12 to eax
    # max/ecx = segments->data + segments->write
    01/add                          3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # add eax to ecx
$emit-headers:loop:
    # if (curr-segment >= max) break
    39/compare                      3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # compare eax with ecx
    0f 83/jump-if-greater-or-equal-unsigned  $emit-headers:end/disp32
#?     # dump curr-segment->name {{{
#?     # . write(2/stderr, "about to emit ph entry: segment->name: ")
#?     # . . push args
#?     68/push  "about to emit ph entry: segment->name: "/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . clear-stream(Stderr+4)
#?     # . . save eax
#?     50/push-eax
#?     # . . push args
#?     b8/copy-to-eax  Stderr/imm32
#?     05/add-to-eax  4/imm32
#?     50/push-eax
#?     # . . call
#?     e8/call  clear-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # . . restore eax
#?     58/pop-to-eax
#?     # . print-int32-buffered(Stderr, &curr-segment)
#?     # . . push args
#?     50/push-eax
#?     68/push  Stderr/imm32
#?     # . . call
#?     e8/call  print-int32-buffered/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . flush(Stderr)
#?     # . . push args
#?     68/push  Stderr/imm32
#?     # . . call
#?     e8/call  flush/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # . write(2/stderr, " -> ")
#?     # . . push args
#?     68/push  " -> "/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . print-int32-buffered(Stderr, curr-segment->name)
#?     # . . push args
#?     ff          6/subop/push        0/mod/indirect  0/rm32/eax    .           .             .           .           .               .                 # push *eax
#?     68/push  Stderr/imm32
#?     # . . call
#?     e8/call  print-int32-buffered/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . flush(Stderr)
#?     # . . push args
#?     68/push  Stderr/imm32
#?     # . . call
#?     e8/call  flush/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # . write(2/stderr, "\n")
#?     # . . push args
#?     68/push  "\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
#?     # write(2/stderr, "emit-segment-header\n") {{{
#?     # . . push args
#?     68/push  "emit-segment-header\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
    # emit-elf-program-header-entry(out, curr-segment)
    # . . push args
    50/push-eax
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    # . . call
    e8/call  emit-elf-program-header-entry/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # curr-segment += 16                        # size of a row
    81          0/subop/add         3/mod/direct    0/rm32/eax    .           .             .           .           .               0x10/imm32        # add to eax
    e9/jump  $emit-headers:loop/disp32
$emit-headers:end:
    # . restore registers
    59/pop-to-ecx
    58/pop-to-eax
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

emit-elf-header:  # out : (address buffered-file), segments : (address stream {string, segment-info}), labels : (address stream {string, label-info})
    # pseudocode
    #   *Elf_e_entry = get(labels, "Entry")->address
    #   *Elf_e_phnum = segments->write / 16         # size of a row
    #   emit-hex-array(out, Elf_header)
    #   write-buffered(out, "\n")
    #
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx  # just because we need to call idiv
    # *Elf_e_entry = get(labels, "Entry")->address
    # . eax = labels
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   0x10/disp8      .                 # copy *(ebp+16) to eax
    # . label-info/eax = get(labels, "Entry", row-size=16, "label table")
    # . . push args
    68/push  "label table"/imm32
    68/push  0x10/imm32/row-size
    68/push  "Entry"/imm32
    50/push-eax
    # . . call
    e8/call  get/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
    # . eax = label-info->address
    8b/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           0/r32/eax   8/disp8         .                 # copy *(eax+8) to eax
    # . *Elf_e_entry = eax
    89/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Elf_e_entry/disp32                # copy eax to *Elf_e_entry
    # *Elf_e_phnum = segments->write / 0x10
    # . eax = segments
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   0xc/disp8       .                 # copy *(ebp+12) to eax
    # . len/eax = segments->write
    8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           0/r32/eax   .               .                 # copy *eax to eax
    # . eax = len / 0x10  (destroying edx)
    b9/copy-to-ecx  0x10/imm32
    31/xor                          3/mod/direct    2/rm32/edx    .           .             .           2/r32/edx   .               .                 # clear edx
    f7          7/subop/idiv        3/mod/direct    1/rm32/ecx    .           .             .           .           .               .                 # divide edx:eax by ecx, storing quotient in eax and remainder in edx
    # . *Elf_e_phnum = eax
    89/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Elf_e_phnum/disp32                # copy eax to *Elf_e_phnum
    # emit-hex-array(out, Elf_header)
    # . . push args
    68/push  Elf_header/imm32
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    # . . call
    e8/call  emit-hex-array/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # write-buffered(out, "\n")
    # . . push args
    68/push  "\n"/imm32
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    # . . call
    e8/call  write-buffered/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
$emit-elf-header:end:
    # . restore registers
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

emit-elf-program-header-entry:  # out : (address buffered-file), curr-segment : (address {string, segment-info})
    # pseudocode:
    #   *Elf_p_offset = curr-segment->file-offset
    #   *Elf_p_vaddr = curr-segment->address
    #   *Elf_p_paddr = curr-segment->address
    #   *Elf_p_filesz = curr-segment->size
    #   *Elf_p_memsz = curr-segment->size
    #   if curr-segment->name == "code"
    #     *Elf_p_flags = 5  # r-x
    #   else
    #     *Elf_p_flags = 6  # rw-
    #   emit-hex-array(out, Elf_program_header_entry)
    #   write-buffered(out, "\n")
    #
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # . save registers
    50/push-eax
    56/push-esi
    # esi = curr-segment
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   0xc/disp8       .                 # copy *(ebp+12) to esi
    # *Elf_p_offset = curr-segment->file-offset
    # . eax = curr-segment->file-offset
    8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           0/r32/eax   8/disp8         .                 # copy *(esi+8) to eax
    # . *Elf_p_offset = eax
    89/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Elf_p_offset/disp32               # copy eax to *Elf_p_offset
    # *Elf_p_vaddr = curr-segment->address
    # . eax = curr-segment->address
    8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           0/r32/eax   4/disp8         .                 # copy *(esi+4) to eax
    # . *Elf_p_vaddr = eax
    89/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Elf_p_vaddr/disp32                # copy eax to *Elf_p_vaddr
    # *Elf_p_paddr = curr-segment->address
    89/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Elf_p_paddr/disp32                # copy eax to *Elf_p_paddr
    # *Elf_p_filesz = curr-segment->size
    # . eax = curr-segment->size
    8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           0/r32/eax   0xc/disp8       .                 # copy *(esi+12) to eax
    # . *Elf_p_filesz = eax
    89/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Elf_p_filesz/disp32               # copy eax to *Elf_p_filesz
    # *Elf_p_memsz = curr-segment->size
    89/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Elf_p_memsz/disp32                # copy eax to *Elf_p_memsz
    # if (!string-equal?(curr-segment->name, "code") goto next check
    # . eax = curr-segment->name
    8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           0/r32/eax   .               .                 # copy *esi to eax
    # . eax = string-equal?(curr-segment->name, "code")
    # . . push args
    68/push  "code"/imm32
    50/push-eax
    # . . call
    e8/call  string-equal?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . if (eax == 0) goto next check
    3d/compare-eax-and  0/imm32
    74/jump-if-equal  $emit-elf-program-header-entry:data/disp8
    # *Elf_p_flags = r-x
    c7          0/subop/copy        0/mod/indirect  5/rm32/.disp32            .             .           .           Elf_p_flags/disp32  5/imm32       # copy to *Elf_p_flags
    eb/jump  $emit-elf-program-header-entry:really-emit/disp8
$emit-elf-program-header-entry:data:
    # otherwise *Elf_p_flags = rw-
    c7          0/subop/copy        0/mod/indirect  5/rm32/.disp32            .             .           .           Elf_p_flags/disp32  6/imm32       # copy to *Elf_p_flags
$emit-elf-program-header-entry:really-emit:
    # emit-hex-array(out, Elf_program_header_entry)
    # . . push args
    68/push  Elf_program_header_entry/imm32
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    # . . call
    e8/call  emit-hex-array/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # write-buffered(out, "\n")
    # . . push args
    68/push  "\n"/imm32
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    # . . call
    e8/call  write-buffered/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
$emit-elf-program-header-entry:end:
    # . restore registers
    5e/pop-to-esi
    58/pop-to-eax
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

# - some helpers for tests

stream-add4:  # in : (address stream byte), key : address, val1 : address, val2 : address, val3 : address
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    56/push-esi
    # esi = in
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
    # curr/eax = in->data + in->write
    # . eax = in->write
    8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           0/r32/eax   .               .                 # copy *esi to eax
    # . eax = esi+eax+12
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/esi  0/index/eax   .           0/r32/eax   0xc/disp8       .                 # copy esi+eax+12 to eax
    # max/edx = in->data + in->length
    # . edx = in->length
    8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           2/r32/edx   8/disp8         .                 # copy *(esi+8) to edx
    # . edx = esi+edx+12
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/esi  2/index/edx   .           2/r32/edx   0xc/disp8       .                 # copy esi+edx+12 to edx
    # if (curr >= max) abort
    39/compare                      3/mod/direct    0/rm32/eax    .           .             .           2/r32/edx   .               .                 # compare eax with edx
    73/jump-if-greater-or-equal-unsigned  $stream-add4:abort/disp8
    # *curr = key
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         1/r32/ecx   0xc/disp8       .                 # copy *(ebp+12) to ecx
    89/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy ecx to *eax
    # curr += 4
    05/add-to-eax  4/imm32
    # if (curr >= max) abort
    39/compare                      3/mod/direct    0/rm32/eax    .           .             .           2/r32/edx   .               .                 # compare eax with edx
    73/jump-if-greater-or-equal-unsigned  $stream-add4:abort/disp8
    # *curr = val1
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         1/r32/ecx   0x10/disp8      .                 # copy *(ebp+16) to ecx
    89/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy ecx to *eax
    # curr += 4
    05/add-to-eax  4/imm32
    # if (curr >= max) abort
    39/compare                      3/mod/direct    0/rm32/eax    .           .             .           2/r32/edx   .               .                 # compare eax with edx
    73/jump-if-greater-or-equal-unsigned  $stream-add4:abort/disp8
    # *curr = val2
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         1/r32/ecx   0x14/disp8      .                 # copy *(ebp+20) to ecx
    89/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy ecx to *eax
    # curr += 4
    05/add-to-eax  4/imm32
    # if (curr >= max) abort
    39/compare                      3/mod/direct    0/rm32/eax    .           .             .           2/r32/edx   .               .                 # compare eax with edx
    73/jump-if-greater-or-equal-unsigned  $stream-add4:abort/disp8
    # *curr = val3
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         1/r32/ecx   0x18/disp8      .                 # copy *(ebp+24) to ecx
    89/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy ecx to *eax
    # in->write += 16
    81          0/subop/add         0/mod/indirect  6/rm32/esi    .           .             .           .           .               0x10/imm32        # add to *esi
$stream-add4:end:
    # . restore registers
    5e/pop-to-esi
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

$stream-add4:abort:
    # . _write(2/stderr, error)
    # . . push args
    68/push  "overflow in stream-add4\n"/imm32
    68/push  2/imm32/stderr
    # . . call
    e8/call  _write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . syscall(exit, 1)
    bb/copy-to-ebx  1/imm32
    b8/copy-to-eax  1/imm32/exit
    cd/syscall  0x80/imm8
    # never gets here

# some variants of 'trace' that take multiple arguments in different combinations of types:
#   n: int
#   c: character [4-bytes, will eventually be UTF-8]
#   s: (address string)
#   l: (address slice)
# one gotcha: 's5' must not be empty

trace-sssns:  # s1 : (address string), s2 : (address string), s3 : (address string), n4 : int, s5 : (address string)
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # write(*Trace-stream, s1)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # write(*Trace-stream, s2)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # write(*Trace-stream, s3)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # print-int32(*Trace-stream, n4)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8      .                 # push *(ebp+20)
    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
    # . . call
    e8/call  print-int32/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # trace(s5)  # implicitly adds a newline and finalizes the trace line
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x18/disp8      .                 # push *(ebp+24)
    # . . call
    e8/call  trace/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
$trace-sssns:end:
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-trace-sssns:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . *Trace-stream->write = 0
    8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Trace-stream/disp32               # copy *Trace-stream to eax
    c7          0/subop/copy        0/mod/direct    0/rm32/eax    .           .             .           .           .               0/imm32           # clear *eax
    # trace-sssns("A" "b" "c " 3 " e")
    # . . push args
    68/push  " e"/imm32
    68/push  3/imm32
    68/push  "c "/imm32
    68/push  "b"/imm32
    68/push  "A"/imm32
    # . . call
    e8/call  trace-sssns/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
#?     # dump *Trace-stream {{{
#?     # . write(2/stderr, "^")
#?     # . . push args
#?     68/push  "^"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write-stream(2/stderr, *Trace-stream)
#?     # . . push args
#?     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write(2/stderr, "$\n")
#?     # . . push args
#?     68/push  "$\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
    # check-trace-contains("Abc 0x00000003 e")
    # . . push args
    68/push  "F - test-trace-sssns"/imm32
    68/push  "Abc 0x00000003 e"/imm32
    # . . call
    e8/call  check-trace-contains/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

trace-snsns:  # s1 : (address string), n2 : int, s3 : (address string), n4 : int, s5 : (address string)
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # write(*Trace-stream, s1)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # print-int32(*Trace-stream, n2)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
    # . . call
    e8/call  print-int32/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # write(*Trace-stream, s3)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # print-int32(*Trace-stream, n4)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8      .                 # push *(ebp+20)
    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
    # . . call
    e8/call  print-int32/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # trace(s5)  # implicitly adds a newline and finalizes the trace line
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x18/disp8      .                 # push *(ebp+24)
    # . . call
    e8/call  trace/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
$trace-snsns:end:
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-trace-snsns:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . *Trace-stream->write = 0
    8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Trace-stream/disp32               # copy *Trace-stream to eax
    c7          0/subop/copy        0/mod/direct    0/rm32/eax    .           .             .           .           .               0/imm32           # clear *eax
    # trace-snsns("A " 2 " c " 3 " e")
    # . . push args
    68/push  " e"/imm32
    68/push  3/imm32
    68/push  " c "/imm32
    68/push  2/imm32
    68/push  "A "/imm32
    # . . call
    e8/call  trace-snsns/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
#?     # dump *Trace-stream {{{
#?     # . write(2/stderr, "^")
#?     # . . push args
#?     68/push  "^"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write-stream(2/stderr, *Trace-stream)
#?     # . . push args
#?     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write(2/stderr, "$\n")
#?     # . . push args
#?     68/push  "$\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
    # check-trace-contains("Abc 0x00000003 e")
    # . . push args
    68/push  "F - test-trace-snsns"/imm32
    68/push  "A 0x00000002 c 0x00000003 e"/imm32
    # . . call
    e8/call  check-trace-contains/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

trace-slsls:  # s1 : (address string), l2 : (address slice), s3 : (address string), l4 : (address slice), s5 : (address string)
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # write(*Trace-stream, s1)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # write-slice(*Trace-stream, l2)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
    # . . call
    e8/call  write-slice/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # write(*Trace-stream, s3)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # write-slice(*Trace-stream, l4)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8      .                 # push *(ebp+20)
    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
    # . . call
    e8/call  write-slice/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # trace(s5)  # implicitly adds a newline and finalizes the trace line
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x18/disp8      .                 # push *(ebp+24)
    # . . call
    e8/call  trace/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
$trace-slsls:end:
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-trace-slsls:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . *Trace-stream->write = 0
    8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Trace-stream/disp32               # copy *Trace-stream to eax
    c7          0/subop/copy        0/mod/direct    0/rm32/eax    .           .             .           .           .               0/imm32           # clear *eax
    # (eax..ecx) = "b"
    b8/copy-to-eax  "b"/imm32
    8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    05/add-to-eax  4/imm32
    # var b/ebx : (address slice) = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           4/r32/esp   .               .                 # copy esp to ebx
    # (eax..ecx) = "d"
    b8/copy-to-eax  "d"/imm32
    8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    05/add-to-eax  4/imm32
    # var d/edx : (address slice) = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
    # trace-slsls("A" b "c" d "e")
    # . . push args
    68/push  "e"/imm32
    52/push-edx
    68/push  "c"/imm32
    53/push-ebx
    68/push  "A"/imm32
    # . . call
    e8/call  trace-slsls/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
#?     # dump *Trace-stream {{{
#?     # . write(2/stderr, "^")
#?     # . . push args
#?     68/push  "^"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write-stream(2/stderr, *Trace-stream)
#?     # . . push args
#?     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write(2/stderr, "$\n")
#?     # . . push args
#?     68/push  "$\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
    # check-trace-contains("Abcde")
    # . . push args
    68/push  "F - test-trace-slsls"/imm32
    68/push  "Abcde"/imm32
    # . . call
    e8/call  check-trace-contains/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

trace-slsns:  # s1 : (address string), l2 : (address slice), s3 : (address string), n4 : int, s5 : (address string)
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # write(*Trace-stream, s1)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # write-slice(*Trace-stream, l2)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
    # . . call
    e8/call  write-slice/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # write(*Trace-stream, s3)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # print-int32(*Trace-stream, n4)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8      .                 # push *(ebp+20)
    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
    # . . call
    e8/call  print-int32/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # trace(s5)  # implicitly adds a newline and finalizes the trace line
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x18/disp8      .                 # push *(ebp+24)
    # . . call
    e8/call  trace/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
$trace-slsns:end:
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-trace-slsns:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . *Trace-stream->write = 0
    8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Trace-stream/disp32               # copy *Trace-stream to eax
    c7          0/subop/copy        0/mod/direct    0/rm32/eax    .           .             .           .           .               0/imm32           # clear *eax
    # (eax..ecx) = "b"
    b8/copy-to-eax  "b"/imm32
    8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    05/add-to-eax  4/imm32
    # var b/ebx : (address slice) = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           4/r32/esp   .               .                 # copy esp to ebx
    # trace-slsls("A" b "c " 3 " e")
    # . . push args
    68/push  " e"/imm32
    68/push  3/imm32
    68/push  "c "/imm32
    53/push-ebx
    68/push  "A"/imm32
    # . . call
    e8/call  trace-slsns/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
#?     # dump *Trace-stream {{{
#?     # . write(2/stderr, "^")
#?     # . . push args
#?     68/push  "^"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write-stream(2/stderr, *Trace-stream)
#?     # . . push args
#?     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write(2/stderr, "$\n")
#?     # . . push args
#?     68/push  "$\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
    # check-trace-contains("Abc 0x00000003 e")
    # . . push args
    68/push  "F - test-trace-slsls"/imm32
    68/push  "Abc 0x00000003 e"/imm32
    # . . call
    e8/call  check-trace-contains/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

trace-slsss:  # s1 : (address string), l2 : (address slice), s3 : (address string), s4 : (address string), s5 : (address string)
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # write(*Trace-stream, s1)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # write-slice(*Trace-stream, l2)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
    # . . call
    e8/call  write-slice/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # write(*Trace-stream, s3)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # write(*Trace-stream, s4)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8      .                 # push *(ebp+20)
    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # trace(s5)  # implicitly adds a newline and finalizes the trace line
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x18/disp8      .                 # push *(ebp+24)
    # . . call
    e8/call  trace/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
$trace-slsss:end:
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-trace-slsss:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . *Trace-stream->write = 0
    8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Trace-stream/disp32               # copy *Trace-stream to eax
    c7          0/subop/copy        0/mod/direct    0/rm32/eax    .           .             .           .           .               0/imm32           # clear *eax
    # (eax..ecx) = "b"
    b8/copy-to-eax  "b"/imm32
    8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    05/add-to-eax  4/imm32
    # var b/ebx : (address slice) = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           4/r32/esp   .               .                 # copy esp to ebx
    # trace-slsss("A" b "c" "d" "e")
    # . . push args
    68/push  "e"/imm32
    68/push  "d"/imm32
    68/push  "c"/imm32
    53/push-ebx
    68/push  "A"/imm32
    # . . call
    e8/call  trace-slsss/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
#?     # dump *Trace-stream {{{
#?     # . write(2/stderr, "^")
#?     # . . push args
#?     68/push  "^"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write-stream(2/stderr, *Trace-stream)
#?     # . . push args
#?     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write(2/stderr, "$\n")
#?     # . . push args
#?     68/push  "$\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
    # check-trace-contains("Abcde")
    # . . push args
    68/push  "F - test-trace-slsss"/imm32
    68/push  "Abcde"/imm32
    # . . call
    e8/call  check-trace-contains/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

num-bytes:  # line : (address stream) -> eax : int
    # pseudocode:
    #   result = 0
    #   while true
    #     var word-slice = next-word(line)
    #     if slice-empty?(word-slice)             # end of line
    #       break
    #     if slice-starts-with?(word-slice, "#")  # comment
    #       break
    #     if is-label?(word-slice)                # no need for label declarations anymore
    #       break
    #     if slice-equal?(word-slice, "==")
    #       break                                 # no need for segment header lines
    #     result += compute-width(word-slice)
    #   return result
    #
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # . save registers
    51/push-ecx
    52/push-edx
    53/push-ebx
    # var result/eax = 0
    31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
    # var word-slice/ecx = {0, 0}
    68/push  0/imm32/end
    68/push  0/imm32/start
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
#?     # dump line {{{
#?     # . write(2/stderr, "LL: ")
#?     # . . push args
#?     68/push  "LL: "/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # write-stream(2/stderr, line)
#?     # . . push args
#?     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write(2/stderr, "$\n")
#?     # . . push args
#?     68/push  "$\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
    # . rewind-stream(line)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    # . . call
    e8/call  rewind-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
$num-bytes:loop:
    # next-word(line, word-slice)
    # . . push args
    51/push-ecx
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    # . . call
    e8/call  next-word/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # dump word-slice {{{
#?     # . write(2/stderr, "AA: ")
#?     # . . push args
#?     68/push  "AA: "/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . clear-stream(Stderr+4)
#?     # . . save eax
#?     50/push-eax
#?     # . . push args
#?     b8/copy-to-eax  Stderr/imm32
#?     05/add-to-eax  4/imm32
#?     50/push-eax
#?     # . . call
#?     e8/call  clear-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # . . restore eax
#?     58/pop-to-eax
#?     # . write-slice-buffered(Stderr, word-slice)
#?     # . . push args
#?     51/push-ecx
#?     68/push  Stderr/imm32
#?     # . . call
#?     e8/call  write-slice-buffered/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . flush(Stderr)
#?     # . . push args
#?     68/push  Stderr/imm32
#?     # . . call
#?     e8/call  flush/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # . write(2/stderr, "$\n")
#?     # . . push args
#?     68/push  "$\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
$num-bytes:check0:
    # if (slice-empty?(word-slice)) break
    # . save result
    50/push-eax
    # . eax = slice-empty?(word-slice)
    # . . push args
    51/push-ecx
    # . . call
    e8/call  slice-empty?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . if (eax != 0) break
    3d/compare-eax-and  0/imm32
    # . restore result now that ZF is set
    58/pop-to-eax
    75/jump-if-not-equal  $num-bytes:end/disp8
$num-bytes:check-for-comment:
    # if (slice-starts-with?(word-slice, "#")) break
    # . start/edx = word-slice->start
    8b/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # copy *ecx to edx
    # . c/ebx = *start
    31/xor                          3/mod/direct    3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # clear ebx
    8a/copy-byte                    0/mod/indirect  2/rm32/edx    .           .             .           3/r32/BL    .               .                 # copy byte at *edx to BL
    # . if (ebx == '#') break
    81          7/subop/compare     3/mod/direct    3/rm32/ebx    .           .             .           .           .               0x23/imm32/hash   # compare ebx
    74/jump-if-equal  $num-bytes:end/disp8
$num-bytes:check-for-label:
    # if (slice-ends-with?(word-slice, ":")) break
    # . end/edx = word-slice->end
    8b/copy                         1/mod/*+disp8   1/rm32/ecx    .           .             .           2/r32/edx   4/disp8         .                 # copy *(ecx+4) to edx
    # . c/ebx = *(end-1)
    31/xor                          3/mod/direct    3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # clear ebx
    8a/copy-byte                    1/mod/*+disp8   2/rm32/edx    .           .             .           3/r32/BL    -1/disp8        .                 # copy byte at *ecx to BL
    # . if (ebx == ':') break
    81          7/subop/compare     3/mod/direct    3/rm32/ebx    .           .             .           .           .               0x3a/imm32/colon  # compare ebx
    74/jump-if-equal  $num-bytes:end/disp8
$num-bytes:check-for-segment-header:
    # if (slice-equal?(word-slice, "==")) break
    # . push result
    50/push-eax
    # . eax = slice-equal?(word-slice, "==")
    # . . push args
    68/push  "=="/imm32
    51/push-ecx
    # . . call
    e8/call  slice-equal?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . if (eax != 0) break
    3d/compare-eax-and  0/imm32
    # . restore result now that ZF is set
    58/pop-to-eax
    75/jump-if-not-equal  $num-bytes:end/disp8
$num-bytes:loop-body:
    # result += compute-width-of-slice(word-slice)
    # . copy result to edx
    89/copy                         3/mod/direct    2/rm32/edx    .           .             .           0/r32/eax   .               .                 # copy eax to edx
    # . eax = compute-width-of-slice(word-slice)
    # . . push args
    51/push-ecx
    # . . call
    e8/call compute-width-of-slice/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . eax += result
    01/add                          3/mod/direct    0/rm32/eax    .           .             .           2/r32/edx   .               .                 # add edx to eax
    e9/jump  $num-bytes:loop/disp32
$num-bytes:end:
    # . rewind-stream(line)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    # . . call
    e8/call  rewind-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . reclaim locals
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . restore registers
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-num-bytes-handles-empty-string:
    # if a line starts with '#', return 0
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . clear-stream(_test-input-stream)
    # . . push args
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . clear-stream(_test-output-stream)
    # . . push args
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # no contents in input
    # eax = num-bytes(_test-input-stream)
    # . . push args
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  num-bytes/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-ints-equal(eax, 0, msg)
    # . . push args
    68/push  "F - test-num-bytes-handles-empty-string"/imm32
    68/push  0/imm32/true
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-num-bytes-ignores-comments:
    # if a line starts with '#', return 0
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . clear-stream(_test-input-stream)
    # . . push args
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . clear-stream(_test-output-stream)
    # . . push args
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # initialize input
    # . write(_test-input-stream, "# abcd")
    # . . push args
    68/push  "# abcd"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # eax = num-bytes(_test-input-stream)
    # . . push args
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  num-bytes/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-ints-equal(eax, 0, msg)
    # . . push args
    68/push  "F - test-num-bytes-ignores-comments"/imm32
    68/push  0/imm32/true
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-num-bytes-ignores-labels:
    # if the first word ends with ':', return 0
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . clear-stream(_test-input-stream)
    # . . push args
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . clear-stream(_test-output-stream)
    # . . push args
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # initialize input
    # . write(_test-input-stream, "ab: # cd")
    # . . push args
    68/push  "ab: # cd"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # eax = num-bytes(_test-input-stream)
    # . . push args
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  num-bytes/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-ints-equal(eax, 0, msg)
    # . . push args
    68/push  "F - test-num-bytes-ignores-labels"/imm32
    68/push  0/imm32/true
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-num-bytes-ignores-segment-headers:
    # if the first word is '==', return 0
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . clear-stream(_test-input-stream)
    # . . push args
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . clear-stream(_test-output-stream)
    # . . push args
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # initialize input
    # . write(_test-input-stream, "== ab cd")
    # . . push args
    68/push  "== ab cd"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # eax = num-bytes(_test-input-stream)
    # . . push args
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  num-bytes/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-ints-equal(eax, 0, msg)
    # . . push args
    68/push  "F - test-num-bytes-ignores-segment-headers"/imm32
    68/push  0/imm32/true
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-num-bytes-counts-words-by-default:
    # without metadata, count words
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . clear-stream(_test-input-stream)
    # . . push args
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . clear-stream(_test-output-stream)
    # . . push args
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # initialize input
    # . write(_test-input-stream, "ab cd ef")
    # . . push args
    68/push  "ab cd ef"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # eax = num-bytes(_test-input-stream)
    # . . push args
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  num-bytes/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-ints-equal(eax, 3, msg)
    # . . push args
    68/push  "F - test-num-bytes-counts-words-by-default"/imm32
    68/push  3/imm32/true
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-num-bytes-ignores-trailing-comment:
    # trailing comments appropriately ignored
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . clear-stream(_test-input-stream)
    # . . push args
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . clear-stream(_test-output-stream)
    # . . push args
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # initialize input
    # . write(_test-input-stream, "ab cd # ef")
    # . . push args
    68/push  "ab cd # ef"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # eax = num-bytes(_test-input-stream)
    # . . push args
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  num-bytes/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-ints-equal(eax, 2, msg)
    # . . push args
    68/push  "F - test-num-bytes-ignores-trailing-comment"/imm32
    68/push  2/imm32/true
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-num-bytes-handles-imm32:
    # if a word has the /imm32 metadata, count it as 4 bytes
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . clear-stream(_test-input-stream)
    # . . push args
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . clear-stream(_test-output-stream)
    # . . push args
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # initialize input
    # . write(_test-input-stream, "ab cd/imm32 ef")
    # . . push args
    68/push  "ab cd/imm32 ef"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # eax = num-bytes(_test-input-stream)
    # . . push args
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  num-bytes/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-ints-equal(eax, 6, msg)
    # . . push args
    68/push  "F - test-num-bytes-handles-imm32"/imm32
    68/push  6/imm32/true
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

== data

# This block of bytes gets copied to the start of the output ELF file, with
# some fields filled in.
# http://www.sco.com/developers/gabi/latest/ch4.eheader.html
Elf_header:
  # - length
  0x34/imm32
  # - data
$e_ident:
  7f 45/E 4c/L 46/F
  01/32-bit  01/little-endian  01/file-version  00/no-os-extensions
  00 00 00 00 00 00 00 00  # 8 bytes of padding
$e_type:
  02 00
$e_machine:
  03 00
$e_version:
  1/imm32
Elf_e_entry:
  0x09000000/imm32  # approximate default; must be updated
$e_phoff:
  0x34/imm32  # offset for the 'program header table' containing segment headers
$e_shoff:
  0/imm32  # no sections
$e_flags:
  0/imm32  # unused
$e_ehsize:
  0x34 00
$e_phentsize:
  0x20 00
Elf_e_phnum:
  00 00  # number of segments; must be updated
$e_shentsize:
  00 00  # no sections
$e_shnum:
  00 00
$e_shstrndx:
  00 00

# This block of bytes gets copied after the Elf_header once for each segment.
# Some fields need filling in each time.
# https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-83432/index.html
Elf_program_header_entry:
  # - length
  0x20/imm32
  # - data
$p_type:
  1/imm32/PT_LOAD
Elf_p_offset:
  0/imm32  # byte offset in the file at which a segment begins; must be updated
Elf_p_vaddr:
  0/imm32  # starting address to store the segment at before running the program
Elf_p_paddr:
  0/imm32  # should have same value as Elf_p_vaddr
Elf_p_filesz:
  0/imm32
Elf_p_memsz:
  0/imm32  # should have same value as Elf_p_filesz
Elf_p_flags:
  6/imm32/rw-  # read/write/execute permissions for the segment; must be updated for the code segment
$p_align:
  # we hold this constant; changing it will require adjusting the way we
  # compute the starting address for each segment
  0x1000/imm32

# . . vim:nowrap:textwidth=0