27
Fri, Dec
0 New Articles

Investigate the Undocumented _LSPCO System Built-in

RPG
Typography
  • Smaller Small Medium Big Bigger
  • Default Helvetica Segoe Georgia Times

The _LSPCO system built-in accepts a space pointer as its input and returns the origin of addressable storage of the "space" addressed by the space pointer.

 

 

In my previous article, A More Complete View of the Machine Interface of IBM i, I introduced a technique that Gene Gaunt invented to retrieve all system built-ins supported by an IBM i release. You might have noticed that many of the system built-ins retrieved via Gene's technique have never been documented publicly. One of the undocumented system built-ins is _LSPCO.

 

I infer that the name of the _LSPCO system built-in (which is also an NMI instruction) stands for Load Space Origin. The _LSPCO system built-in accepts a space pointer as its input and returns the origin (the beginning address) of addressable storage of the "space" addressed by the space pointer. The "space" can be an MI space object, the automatic stack of an MI thread, the static storage of an activation group, a pointer-based heap space allocated for an activation group, or the Teraspace of an MI process. _LSPCO is an unblocked system built-in, which means that, if you know the correct prototype of it, you can utilize this system built-in in your ILE high-level language (HLL) programs.

 

This article will lead you to the _LSPCO system built-in and show you how to utilize it in your HLL programs.

The Prototype of _LSPCO

 

Issuing a blocked MI instruction from a program when the thread is running in user state will raise a hex 4401 (Object Domain or Hardware Storage Protection Violation) exception (aka MCH6801). A user program that invokes a blocked system built-in will also be stopped by a hex 2A1B (Instruction Stream Not Valid) exception with reason code 22 (which means A blocked built-in function is called). _LSPCO is not a blocked system built-in, so you can utilize it in your user programs written in an ILE HLL.

 

I tried a few times to find out the prototype of the _LSPCO system built-in. _LSPCO accepts a space pointer (identifying the space) passed by value as its only input parameter and returns the origin of the space via a space pointer.

 

The prototypes of _LSPCO declared in ILE C and ILE RPG are the following, respectively:

 

ILE C

# pragma linkage(_LSPCO, builtin)

void* _LSPCO(void*);

 

ILE RPG

     d lspco          pr             *   extproc('_LSPCO')

     d       spp                           *   value

How Does _LSPCO Work?

The following is the source of an ILE C program (lspco02.c) that invokes the _LSPCO system built-in to retrieve the origin (the beginning address) of the automatic stack of the current thread and then print the returned address to stdout.

 

# include <stdlib.h>

# include <string.h>

# include <stdio.h>

# include <mih/cvthc.h>

 

# pragma linkage(_LSPCO, builtin)

void* _LSPCO(void*);

 

# pragma linkage(_MODASA, builtin)

void *_MODASA(unsigned);

 

static void *p = NULL;

 

void func() {

p = _LSPCO(p); // stmt 1

}

 

int main() {

char addr[33] = {0};

p = _MODASA(0x100);

func();

cvthc(addr, &p, 32);

printf("SPP: %s\x25", addr);

return 0;

}

 

Try choosing different storage models (SLS or Teraspace) for the compiled program via the STGMDL parameter of the CRTBNDC command and observe the output of program LSPCO02.

 

The following are the NMI instructions generated (at VRM540) for the only statement of the func() procedure:

 

     OFFSET           000000AC

     OPCODE           LOD1

          OPERAND 1       2

     OFFSET           000000B4

     OPCODE           PALI

          OPERAND 1       3

          OPERAND 2       2

     OFFSET           000000C0

     OPCODE           LSPCO

     OFFSET           000000C4

     OPCODE           STR1

          OPERAND 1       2

 

As you might have noticed, the _LSPCO system built-in shares the same name as its corresponding NMI instruction. That's probably why the naming convention applied to _LSPCO is so different from the naming convention of the majority of the MI instructions we are familiar with.

 

Note that the PowerPC instructions generated for the _LSPCO system built-in do not involve invocation of any LIC routine; they are just inlined PowerPC instructions generated into the user code of the result program. The PowerPC instructions generated (at VRM540) for the p = _LSPCO(p); statement might look like the following:

 

LOCATION OBJECT TEXT   SOURCE STATEMENT       Notes

-----     -----       -----                 -----

000020   E1040006     LQ 8,0X0(4),6         [1]

000024   792A049C     SELRI 10,9,0,41       [1]

000028   79472720     RLDICL 7,10,4,60       [2]

00002C   29270009     CMPLI 2,1,7,9         [2]

000030   41CA0010     BC 14,10,0X10         [2]

000034   794601E4     RLDICR 6,10,0,39       [2.A]

000038   E8C60018     LD 6,0X18(6)           [2.A]

00003C   48000008     B 0X8                 [2.A]

000040   794605C4       RLDICR 6,10,0,23       [2.B]

000044   E8A08110     LD 5,0X8110(0)         [3]

000048   78CC01E5     RLDICR. 12,6,0,39     [4]

00004C   E9008118     LD 8,0X8118(0)         [3]

000050   78C92720       RLDICL 9,6,4,60       [5]

000054   E8E08178     LD 7,0X8178(0)         [3]

000058   79052B1E     SELRR 5,8,5,38         [4]

00005C   28290009     CMPLI 0,1,9,9         [5]

000060   7C0103E6     SETTAG                 [7]

000064    78E52B1E     SELRR 5,7,5,38         [5]

000068   60A80000       ORI 8,5,0             [6]

00006C   60C90000       ORI 9,6,0             [6]

000070   F9040002     STQ 8,0X0(4)           [7]

 

Notes

[1] The 16-byte input space pointer is loaded into General Purpose Register (GPR) 8 and GPR 9 by the LQ instruction. (I will refer to GPR n simply as rn in the remaining portion of this article.) The SELRI instruction checks the input pointer for validity (if the MI pointer tag bits are set) and sets r10 correspondingly. r10 is set to all hex 00 if it is an invalid pointer (the MI pointer tag bits are off); otherwise, it is set to the 8-byte address portion of the pointer. (The higher 8 bytes of a 16-byte MI space pointer are the pointer type bytes and the lower 8 bytes are the address portion.)

[2] Check for Teraspace address by checking the higher 4 bits of the address portion (stored in r10). If the higher 4 bits are equal to hex 9 (which means the input space pointer addresses the Teraspace storage), the execution is branched to the RLDICR 6,10,0,23 instruction at offset hex 000040 (see [2.B]).

[2.A] For a single-level store (SLS) space pointer, the higher 5 bytes of the address portion (the segment ID) plus hex 000000 are the start of the SLS segment. The RLDICR 6,10,0,39 instruction loads the address of the beginning of the SLS segment into r6. At the beginning of a SLS segment is the 32-byte segment header, the 8-byte field at offset hex 18, which is the address of the associated space. For the base (and the only) segment of an MI space object or a segment allocated for automatic storage, static storage, or heap storage, the associated space field of the segment header is the origin of the addressable storage of the SLS segment.

[2.B] For a Teraspace address, the higher 3 bytes of the pointer's address portion plus hex 0000000000 (the origin of the Teraspace) are placed into r6 as the address portion of the space pointer to return.

[3] Load the 8-byte pointer type values for a SLS space pointer (hex 8000000000000000), an invalid pointer (hex AF00000000000000), and a Teraspace space pointer (hex 4000000000000000) into r5, r8, and r7 respectively.

[4] The RLDICR. 12,6,0,39 instruction and the SELRR 5,8,5,38 instruction set the result pointer type bytes to r8 (hex AF00000000000000) if the higher 5 bytes of r6 (address portion of the result pointer) is hex 0000000000; otherwise, the resulting pointer type bytes are set to r5 (hex 8000000000000000). In other words, if the higher 5 bytes of a space pointer is hex 0000000000, it is regarded as an invalid pointer.

[5] The higher 4 bits of r6 (address portion of the space pointer to return) is stored in the lowest 4 bits of r9 by the RLDICL 9,6,4,60 instruction, and the other bits of r9 are cleared. r9 is then compared with the value hex 9 by the CMPLI 0,1,9,9 instruction. If r9 is equal to hex 9, the 8-byte pointer type of the Teraspace space pointer (hex 4000000000000000) stored in r7 is selected for the resulting pointer type bytes (in r5); otherwise, the content of r5 remains unchanged.

[6] The resulting pointer type bytes (in r5) are stored in r8, and the resulting address (in r6) of the origin of the space is stored in r9 by the ORI 8,5,0 and ORI 9,6,0 instructions, respectively.

[7] The SETTAG and STQ 8,0X0(4) instructions finally store the 16-byte space pointer (in r8 and r9) to user storage. Note that in the above-shown example C program, space pointer p (which is a static variable) is either used as the operand of _LSPCO or is used to receive the return value of _LSPCO. So the returned space pointer is stored in the same place where the input space pointer is loaded: the start of the static storage frame (SSF) allocated for the program at run time.

 

What we know from the PowerPC instructions generated for _LSPCO into the user code of a user program?

  1. The pointer type bytes (higher 8 bytes) of a SLS space pointer and a Teraspace space pointer are hex 8000000000000000 and hex 4000000000000000, respectively.
  2. The higher 4 bits of a Teraspace address is hex 9. So what does this mean? The higher 3 bytes are the identifier of a Teraspace (let's call it TSID) of an MI process, and the origin of a Teraspace is the TSID plus hex 0000000000 (TSID-0000000000). Through experiments and debugging, you can easily determine that system state Teraspace storage is allocated starting at address TSID-0000000000 and user state Teraspace storage is allocated starting at address TSID-8000000000.
  3. The origin of an MI space object, the automatic stack of an MI thread, the static storage of an activation group, or a pointer-based heap space is stored in the associated space field (at offset hex 18) of the segment header of the SLS segment allocated for the MI space object, the automatic stack, the static storage, or the pointer-based heap space.

 

For detailed documentation about the PowerPC instruction set, please refer to the Assembler language reference in the AIX Information Center. The Programming Environments Manual for 64-bit Microprocessors would be a nice reference for the PowerPC architecture. Also note that instructions such as SETTAG (Set Tag) and SELRR are IBM i–specific PowerPC instructions. I've never found public documentation about these instructions. However, they have been discussed by several AS/400 gurus in the MI400 mailing list.

A Real RPG Example

Here is a real RPG example (lspco01.rpgle) that uses the _LSPCO system built-in to retrieve the origins of:

  • An MI space object
  • The automatic stack of the current thread
  • The static storage of the activation group in which the program is activated
  • A pointer-based heap space allocated for the activation group in which the program is activated
  • The Teraspace of the MI process

 

lspco01.rpgle

 

     h dftactgrp(*no) bnddir('QC2LE')

 

     /if defined(HAVE_I5TOOLKIT)

     /copy mih-pgmexec

     /copy ts

     /else

     /**

     * @BIF _MODASA (Modify Automatic Storage Allocation (MODASA))

     *

     * @remark Note that unlike MI instruction MODASA, builtin

     *         _MODASA cannot be used to truncate ASF. Passing a

     *         negative value to _MODASA will raise a Scalar Value

     *         Invalid exception (3203)

     */

     d modasa         pr             *   extproc('_MODASA')

     d       mod_size                 10u 0 value

     * Allocate Teraspace heap storage

     d ts_malloc       pr             *   extproc('_C_TS_malloc')

     d       size                      10i 0 value

     * Returns a space pointer addressing the System Entry Point Table (SEPT)

     d sysept         pr             *   extproc('_SYSEPT')

     /endif

     * System built-in _LSPCO (Load Space Origin)

     d lspco           pr              *     extproc('_LSPCO')

     d       spp                           *   value

     * Display the content of an input MI pointer

     d dsp_ptr         pr

     d                                 *

 

     d a               s             80a     based(a@)

   d origin@         s               *

     d i_static       s             80a   inz('i static')

 

     /free

           // [x] Apply _LSPCO to a space pointer addressing

           //     a space object

           a@ = sysept();

           origin@ = lspco(a@);

           dsp_ptr(origin@);

 

           // [x] Apply _LSPCO to a space pointer addressing

           //     the SLS automatic stack

           a@ = modasa(%size(a));

           origin@ = lspco(a@);

           dsp_ptr(origin@);

 

           // [x] Apply _LSPCO to a space pointer addressing

           //     the static storage

           a@ = %addr(i_static);

           origin@ = lspco(a@);

           dsp_ptr(origin@);

 

           // [x] Apply _LSPCO to a space pointer addressing

           //     the SLS heap stroage

           a@ = %alloc(%size(a@));

           origin@ = lspco(a@);

           dsp_ptr(origin@);

 

           // [x] Apply _LSPCO to a space pointer addressing

           //     the Teraspace heap

           a@ = ts_malloc(80);

           origin@ = lspco(a@);

           dsp_ptr(origin@);

 

           *inlr = *on;

     /end-free

 

     p dsp_ptr         b

     * cvthc()

     d cvthc           pr                 extproc('cvthc')

     d                               1a     options(*varsize)

    d                               1a     options(*varsize)

     d                               10u 0 value

 

     d dsp_ptr         pi

     d     ptr@                         *

 

     d ptr_addr@       s               *

     d                 ds                based(ptr_addr@)

     d hi8                           8a  

     d lo8                           8a

     d hi16           s             16a

     d lo16           s             16a

 

     /free

           ptr_addr@ = %addr(ptr@);

           cvthc(hi16:hi8:16);

           cvthc(lo16:lo8:16);

           dsply hi16 '' lo16;

     /end-free

     p                 e

 

Calling program LSPCO01, the output might look like the following:

 

     DSPLY   8000000000000000     333EE74D88001000

     DSPLY   8000000000000000     C62EF42483001000

     DSPLY   8000000000000000   D7FF0C60A3001000

     DSPLY   8000000000000000     CA062D7689001000

     DSPLY   4000000000000000   97185C0000000000

 

BLOG COMMENTS POWERED BY DISQUS

LATEST COMMENTS

Support MC Press Online

$

Book Reviews

Resource Center

  • SB Profound WC 5536 Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application. You can find Part 1 here. In Part 2 of our free Node.js Webinar Series, Brian May teaches you the different tooling options available for writing code, debugging, and using Git for version control. Brian will briefly discuss the different tools available, and demonstrate his preferred setup for Node development on IBM i or any platform. Attend this webinar to learn:

  • SB Profound WP 5539More than ever, there is a demand for IT to deliver innovation. Your IBM i has been an essential part of your business operations for years. However, your organization may struggle to maintain the current system and implement new projects. The thousands of customers we've worked with and surveyed state that expectations regarding the digital footprint and vision of the company are not aligned with the current IT environment.

  • SB HelpSystems ROBOT Generic IBM announced the E1080 servers using the latest Power10 processor in September 2021. The most powerful processor from IBM to date, Power10 is designed to handle the demands of doing business in today’s high-tech atmosphere, including running cloud applications, supporting big data, and managing AI workloads. But what does Power10 mean for your data center? In this recorded webinar, IBMers Dan Sundt and Dylan Boday join IBM Power Champion Tom Huntington for a discussion on why Power10 technology is the right strategic investment if you run IBM i, AIX, or Linux. In this action-packed hour, Tom will share trends from the IBM i and AIX user communities while Dan and Dylan dive into the tech specs for key hardware, including:

  • Magic MarkTRY the one package that solves all your document design and printing challenges on all your platforms. Produce bar code labels, electronic forms, ad hoc reports, and RFID tags – without programming! MarkMagic is the only document design and print solution that combines report writing, WYSIWYG label and forms design, and conditional printing in one integrated product. Make sure your data survives when catastrophe hits. Request your trial now!  Request Now.

  • SB HelpSystems ROBOT GenericForms of ransomware has been around for over 30 years, and with more and more organizations suffering attacks each year, it continues to endure. What has made ransomware such a durable threat and what is the best way to combat it? In order to prevent ransomware, organizations must first understand how it works.

  • SB HelpSystems ROBOT GenericIT security is a top priority for businesses around the world, but most IBM i pros don’t know where to begin—and most cybersecurity experts don’t know IBM i. In this session, Robin Tatam explores the business impact of lax IBM i security, the top vulnerabilities putting IBM i at risk, and the steps you can take to protect your organization. If you’re looking to avoid unexpected downtime or corrupted data, you don’t want to miss this session.

  • SB HelpSystems ROBOT GenericCan you trust all of your users all of the time? A typical end user receives 16 malicious emails each month, but only 17 percent of these phishing campaigns are reported to IT. Once an attack is underway, most organizations won’t discover the breach until six months later. A staggering amount of damage can occur in that time. Despite these risks, 93 percent of organizations are leaving their IBM i systems vulnerable to cybercrime. In this on-demand webinar, IBM i security experts Robin Tatam and Sandi Moore will reveal:

  • FORTRA Disaster protection is vital to every business. Yet, it often consists of patched together procedures that are prone to error. From automatic backups to data encryption to media management, Robot automates the routine (yet often complex) tasks of iSeries backup and recovery, saving you time and money and making the process safer and more reliable. Automate your backups with the Robot Backup and Recovery Solution. Key features include:

  • FORTRAManaging messages on your IBM i can be more than a full-time job if you have to do it manually. Messages need a response and resources must be monitored—often over multiple systems and across platforms. How can you be sure you won’t miss important system events? Automate your message center with the Robot Message Management Solution. Key features include:

  • FORTRAThe thought of printing, distributing, and storing iSeries reports manually may reduce you to tears. Paper and labor costs associated with report generation can spiral out of control. Mountains of paper threaten to swamp your files. Robot automates report bursting, distribution, bundling, and archiving, and offers secure, selective online report viewing. Manage your reports with the Robot Report Management Solution. Key features include:

  • FORTRAFor over 30 years, Robot has been a leader in systems management for IBM i. With batch job creation and scheduling at its core, the Robot Job Scheduling Solution reduces the opportunity for human error and helps you maintain service levels, automating even the biggest, most complex runbooks. Manage your job schedule with the Robot Job Scheduling Solution. Key features include:

  • LANSA Business users want new applications now. Market and regulatory pressures require faster application updates and delivery into production. Your IBM i developers may be approaching retirement, and you see no sure way to fill their positions with experienced developers. In addition, you may be caught between maintaining your existing applications and the uncertainty of moving to something new.

  • LANSAWhen it comes to creating your business applications, there are hundreds of coding platforms and programming languages to choose from. These options range from very complex traditional programming languages to Low-Code platforms where sometimes no traditional coding experience is needed. Download our whitepaper, The Power of Writing Code in a Low-Code Solution, and:

  • LANSASupply Chain is becoming increasingly complex and unpredictable. From raw materials for manufacturing to food supply chains, the journey from source to production to delivery to consumers is marred with inefficiencies, manual processes, shortages, recalls, counterfeits, and scandals. In this webinar, we discuss how:

  • The MC Resource Centers bring you the widest selection of white papers, trial software, and on-demand webcasts for you to choose from. >> Review the list of White Papers, Trial Software or On-Demand Webcast at the MC Press Resource Center. >> Add the items to yru Cart and complet he checkout process and submit

  • Profound Logic Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application.

  • SB Profound WC 5536Join us for this hour-long webcast that will explore:

  • Fortra IT managers hoping to find new IBM i talent are discovering that the pool of experienced RPG programmers and operators or administrators with intimate knowledge of the operating system and the applications that run on it is small. This begs the question: How will you manage the platform that supports such a big part of your business? This guide offers strategies and software suggestions to help you plan IT staffing and resources and smooth the transition after your AS/400 talent retires. Read on to learn: